博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
[APIO2014]回文串 manacher 后缀数组
阅读量:4337 次
发布时间:2019-06-07

本文共 4681 字,大约阅读时间需要 15 分钟。

题面:

题解:

  还是这个性质:对于每个串而言,本质不同的回文串最多只有O(n)个。

  所以我们先求出这O(n)个本质不同的回文串,然后对整个串求一次sa。

  然后对于每个回文串,求出它的出现次数,更新答案即可。

  如何用后缀数组求一个串的出现次数?

  因为每个串都必然是某个后缀的前缀。因此我们先找到这个串x,然后在周围二分,寻找一个最大的区间[l, r]使得区间内每个串与x的LCP都大于等于这个串的长度。

  可以证明,这样的区间必然是连续的一个。

  因此在周围分别向上向下二分一下最多能延伸到哪,是否可行用st表维护一下height数组的最小值即可O(1)查询LCP大小。

  

1 // luogu-judger-enable-o2  2 // luogu-judger-enable-o2  3 #include
4 using namespace std; 5 #define R register int 6 #define AC 601000 7 #define ac 601000 8 #define LL long long 9 10 int n, m = 127, pos, maxn; 11 LL ans; 12 int r[ac], sa[AC], rk[AC], p1[AC], p2[AC], b[AC], d[AC];//第几是谁,你是第几, 两个关键字,临时数组,桶 13 int st[AC][19], h[AC], last[AC], length[AC]; 14 char ss[AC], s[ac];//原串,扩充串 15 16 inline void upmax(LL &a, LL b){ 17 if(b > a) a = b; 18 } 19 20 void pre() 21 { 22 scanf("%s", ss + 1), n = strlen(ss + 1); 23 s[0] = '$', s[1] = '#'; 24 for(R i = 1; i <= n; i ++) s[i << 1] = ss[i], s[(i << 1) + 1] = '#';//manacher数组 25 for(R i = 1; i <= n; i ++) sa[i] = i, rk[i] = ss[i];//初始化后缀数组 26 } 27 28 void ssort() 29 { 30 for(R i = 1; i <= n; i ++) ++ d[p2[i]]; 31 for(R i = 1; i <= m; i ++) d[i] += d[i - 1]; 32 for(R i = 1; i <= n; i ++) b[d[p2[i]] --] = i;//给i分配排名(临时sa数组) 33 for(R i = 0; i <= m; i ++) d[i] = 0; 34 35 for(R i = 1; i <= n; i ++) ++ d[p1[i]]; 36 for(R i = 1; i <= m; i ++) d[i] += d[i - 1]; 37 for(R i = n; i; i --) sa[d[p1[b[i]]] --] = b[i];//依次给b[i]分配排名 38 for(R i = 0; i <= m; i ++) d[i] = 0; 39 } 40 41 void sa_sort() 42 { 43 for(R k = 1; k <= n; k <<= 1) 44 { 45 for(R i = 1; i <= n; i ++) 46 p1[i] = rk[i], p2[i] = rk[i + k]; 47 ssort(); 48 int tmp = 1; 49 rk[sa[1]] = 1; 50 for(R i = 2; i <= n; i ++) 51 rk[sa[i]] = (p1[sa[i]] == p1[sa[i - 1]] && p2[sa[i]] == p2[sa[i - 1]]) ? tmp : ++ tmp; 52 if(tmp >= n) break; 53 m = tmp; 54 } 55 } 56 57 void manacher()//获取回文串 58 { 59 int b = 2 * n; 60 for(R i = 1; i <= b; i ++) 61 { 62 r[i] = (maxn > i) ? min(r[(pos << 1) - i], maxn - i + 1) : 1; 63 while(s[i - r[i]] == s[i + r[i]]) ++ r[i]; 64 int t = i + r[i] - 1; 65 if(t > maxn) 66 { 67 for(R j = maxn + 1; j <= t; ++ j) 68 { 69 last[j] = (i << 1) - j;//串的开始是要算的,,,, 70 if(s[j] == '#') continue; 71 length[j] = ((j - last[j]) >> 1) + 1; 72 } 73 pos = i, maxn = t; 74 } 75 } 76 77 /*for(R i = 1; i <= b; i ++) 78 { 79 if(s[i] == '#') continue; 80 length[i] = ((i - last[i]) >> 1) + 1;//(r - l) / 2 + 1算出字母的长度(个数) 81 }*/ 82 } 83 84 void build()//求height数组 85 { 86 //h[sa[1]] = 0; 87 for(R i = 1, k = 0; i <= n; i ++)//按照原串顺序求h 88 { 89 if(k) -- k;//将k变为上一次的h[i] - 1 90 int j = sa[rk[i] - 1]; 91 while(ss[i + k] == ss[j + k] && k <= n) ++ k; 92 h[rk[i]] = k; 93 } 94 } 95 96 int t1[AC], t2[AC];//最接近i的2的n次幂的指数,对应的大小 97 98 void get_st() 99 {100 int tt = 0, tmp = 1;101 for(R i = 1; i <= n; i ++) 102 {103 st[i][0] = h[i];104 if(i == (tmp << 1)) tmp <<= 1, ++ tt;105 t1[i] = tt, t2[i] = tmp;106 }107 tmp = 1;108 for(R i = 1; i <= 18; i ++)109 {110 for(R j = 1; j <= n; j ++)111 st[j][i] = min(st[j][i - 1], st[j + tmp][i - 1]);112 tmp <<= 1;113 } 114 }115 116 bool check(int l, int r, int lim)//看min[l, r]是否>= lim117 {118 int rnt = 0, len = (r - l + 1);119 rnt = min(st[l][t1[len]], st[r - t2[len] + 1][t1[len]]);120 return rnt >= lim;121 }122 123 LL half(int x, int len)//获取出现次数124 {125 int l = 1, r = x;126 while(l < r)//查找前一段里面第一个符合的127 {128 int mid = (l + r) >> 1;129 if(check(mid + 1, x, len)) r = mid;130 else l = mid + 1;131 }132 int ll = l;//记录左边界133 l = x, r = n;134 while(l < r)//查找后一段里面最后一个符合的135 {136 int mid = (l + r + 1) >> 1;137 if(check(x + 1, mid, len)) l = mid;138 else r = mid - 1;139 }140 return r - ll + 1;141 }142 143 void work()144 {145 int b = 2 * n;146 for(R i = 1; i <= b; i ++)147 {148 if(s[i] == '#') continue;149 upmax(ans, 1LL * length[i] * half(rk[last[i] >> 1], length[i]));150 }151 printf("%lld\n", ans);152 }153 154 int main()155 {156 // freopen("in.in", "r", stdin);157 pre();158 sa_sort();159 build();160 get_st();161 manacher();162 work();163 // fclose(stdin);164 return 0;165 }
View Code

 

转载于:https://www.cnblogs.com/ww3113306/p/10066838.html

你可能感兴趣的文章
Provider 模式
查看>>
系统分析与建模6
查看>>
window.onload起冲突解决办法
查看>>
并发量计算研究
查看>>
sqlserver安装相关问题
查看>>
iOS学习系列 - 利用ASIHTTPRequest实现异步队列
查看>>
Oracle11g创建表空间、创建用户、角色授权、导入导出表以及中文字符乱码问题...
查看>>
我对 Window.Open 的认识
查看>>
restore db from production copy
查看>>
jQuery源码的基础知识
查看>>
BZOJ 2049 [Sdoi2008]Cave 洞穴勘测(动态树)
查看>>
LeetCode 第21题 合并有序链表
查看>>
Highcharts学习资料收集
查看>>
测开之路十四:面向对象、继承、重载
查看>>
CBAM(Convolutional Block Attention Module)使用指南
查看>>
类中的静态函数和非静态函数的区别
查看>>
[APIO2014]回文串 manacher 后缀数组
查看>>
[六省联考2017]期末考试 贪心 枚举
查看>>
模块and包
查看>>
【总结】01背包问题
查看>>