BZOJ3676:[APIO2014]回文串(SAM,Manacher)
Description
考虑一个只包含小写拉丁字母的字符串s。我们定义s的一个子串t的“出 现值”为t在s中的出现次数乘以t的长度。请你求出s的所有回文子串中的最 大出现值。
Input
输入只有一行,为一个只包含小写字母(a -z)的非空字符串s。
Output
输出一个整数,为逝查回文子串的最大出现值。
Sample Input
abacaba
【样例输入2]
www
Sample Output
7
【样例输出2]
4
HINT
一个串是回文的,当且仅当它从左到右读和从右到左读完全一样。
在第一个样例中,回文子串有7个:a,b,c,aba,aca,bacab,abacaba,其中:
● a出现4次,其出现值为4:1:1=4
● b出现2次,其出现值为2:1:1=2
● c出现1次,其出现值为l:1:l=l
● aba出现2次,其出现值为2:1:3=6
● aca出现1次,其出现值为1=1:3=3
●bacab出现1次,其出现值为1:1:5=5
● abacaba出现1次,其出现值为1:1:7=7
故最大回文子串出现值为7。
【数据规模与评分】
数据满足1≤字符串长度≤300000。
Solution
垃圾题目卡$SAM+Manacher$做法的空间……害我把所有的结构体全拆开还把$SAM$的$son$数组换成了$map$才过……
首先众所周知,一个串的本质不同的回文子串只有$O(n)$级别,且在$Manacher$过程中右端点右移的情况就是本质不同的回文子串。所以我们可以做一遍$Manacher$把本质不同的回文子串求出来。
假设现在的一个回文子串是$S_{l,r}$,设$SAM$插入$r$的时候的$np$节点为$node_r$,那么我们知道,$S_{l,r}$一定是$node_r$代表的子串的一个后缀,且$S_{l,r}$的出现次数是$right_{node_r}$。
我们可以倍增从$node_r$往上跳,因为越往上跳$right$越大。跳到长度取值范围包括$r-l+1$的节点然后更新答案就可以了。
Code
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<map> 5 #define N (600009) 6 #define LL long long 7 using namespace std; 8 9 int to[N],nxt[N]; 10 int n,m,pos[N],len[N]; 11 int Depth[N],f[N][20]; 12 int head[N],num_edge; 13 int p,q,np,nq,last=1,cnt=1; 14 int fa[N],rig[N],step[N],node[N]; 15 map<int,int>son[N]; 16 LL ans; 17 char s[N>>1],t[N]; 18 19 void add(int u,int v) 20 { 21 to[++num_edge]=v; 22 nxt[num_edge]=head[u]; 23 head[u]=num_edge; 24 } 25 26 void Insert(int x) 27 { 28 p=last; np=last=++cnt; step[np]=step[p]+1; rig[np]=1; 29 while (!son[p][x] && p) son[p][x]=np, p=fa[p]; 30 if (!p) fa[np]=1; 31 else 32 { 33 q=son[p][x]; 34 if (step[q]==step[p]+1) fa[np]=q; 35 else 36 { 37 nq=++cnt; step[nq]=step[p]+1; 38 son[nq]=son[q]; 39 fa[nq]=fa[q]; fa[q]=fa[np]=nq; 40 while (son[p][x]==q) son[p][x]=nq, p=fa[p]; 41 } 42 } 43 } 44 45 void DFS(int x,int fa) 46 { 47 Depth[x]=Depth[fa]+1; f[x][0]=fa; 48 for (int i=1; i<=19; ++i) f[x][i]=f[f[x][i-1]][i-1]; 49 for (int i=head[x]; i; i=nxt[i]) 50 DFS(to[i],x), rig[x]+=rig[to[i]]; 51 } 52 53 void Calc() 54 { 55 for (int i=0; i<n; ++i) Insert(s[i]-'a'), node[i]=np; 56 for (int i=2; i<=cnt; ++i) add(fa[i],i); 57 DFS(1,0); 58 } 59 60 void Solve(int p,int k) 61 { 62 while (t[p+k]=='#' || t[p+k]==')') --k; 63 int x=node[pos[p+k]],y=pos[p+k]-pos[p-k]+1; 64 for (int i=19; i>=0; --i) if (step[f[x][i]]>=y) x=f[x][i]; 65 ans=max(ans,1ll*rig[x]*y); 66 } 67 68 void Manacher() 69 { 70 t[++m]='('; 71 for (int i=0; i<n; ++i) t[++m]='#', t[++m]=s[i], pos[m]=i; 72 t[++m]='#'; t[++m]=')'; 73 74 int x,mid=0,maxn=0; 75 for (int i=1; i<=m; ++i) 76 { 77 if (i>maxn) x=1; 78 else x=min(maxn-i+1,len[mid*2-i]); 79 while (t[i+x]==t[i-x]) Solve(i,x), ++x; 80 len[i]=x; 81 if (i+x-1>maxn) maxn=i+x-1, mid=i; 82 } 83 } 84 85 int main() 86 { 87 scanf("%s",s); n=strlen(s); 88 Calc(); Manacher(); 89 printf("%lld\n",ans); 90 }