BZOJ3676: [Apio2014]回文串(SAM+Manacher/PAM)
Description
考虑一个只包含小写拉丁字母的字符串s。我们定义s的一个子串t的“出
现值”为t在s中的出现次数乘以t的长度。请你求出s的所有回文子串中的最
大出现值。
Input
输入只有一行,为一个只包含小写字母(a -z)的非空字符串s。
Output
输出一个整数,为逝查回文子串的最大出现值。
Sample Input
【样例输入l】
abacaba
【样例输入2]
www
abacaba
【样例输入2]
www
Sample Output
【样例输出l】
7
【样例输出2]
4
7
【样例输出2]
4
解题思路:
1.Manacher+SAM
首先,是不是有人告诉过你本质不同的回文串有O(n)个,就是在Manacher中学过的。
每次在Manacher扩展f[i]时将其在SAM的Parent树中匹配,就是len*wgt最大值。
代码:
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 typedef long long lnt; 5 const int N=600005; 6 const int M=300005; 7 struct sant{ 8 int tranc[26]; 9 int len; 10 int pre; 11 }s[N]; 12 struct pnt{ 13 int hd; 14 int fa[17]; 15 int wgt; 16 }p[N]; 17 int cnt; 18 int dfn; 19 int siz; 20 int fin; 21 int len,m; 22 lnt ans; 23 char tmp[M]; 24 int str[M<<1]; 25 int f[N]; 26 int pos[M<<1]; 27 int endpos[M]; 28 int has[N]; 29 int topo[N]; 30 void Insert(int c) 31 { 32 int nwp,nwq,lsp,lsq; 33 nwp=++siz; 34 p[nwp].wgt=1; 35 s[nwp].len=s[fin].len+1; 36 for(lsp=fin;lsp&&!s[lsp].tranc[c];lsp=s[lsp].pre) 37 s[lsp].tranc[c]=nwp; 38 if(!lsp) 39 s[nwp].pre=1; 40 else{ 41 lsq=s[lsp].tranc[c]; 42 if(s[lsq].len==s[lsp].len+1) 43 s[nwp].pre=lsq; 44 else{ 45 nwq=++siz; 46 s[nwq]=s[lsq]; 47 s[nwq].len=s[lsp].len+1; 48 s[nwp].pre=s[lsq].pre=nwq; 49 while(s[lsp].tranc[c]==lsq) 50 { 51 s[lsp].tranc[c]=nwq; 52 lsp=s[lsp].pre; 53 } 54 } 55 } 56 fin=nwp; 57 return ; 58 } 59 int check(int l,int r) 60 { 61 if(l<1||r>len) 62 return 0; 63 int root=endpos[r]; 64 for(int i=16;i>=0;i--) 65 { 66 if(s[p[root].fa[i]].len>=r-l+1) 67 root=p[root].fa[i]; 68 } 69 ans=std::max(ans,(lnt)(r-l+1)*(lnt)(p[root].wgt)); 70 return (r-l+1)*p[root].wgt; 71 } 72 int main() 73 { 74 scanf("%s",tmp+1); 75 fin=++siz; 76 len=strlen(tmp+1); 77 for(int i=1;i<=len;i++) 78 { 79 Insert(tmp[i]-'a'); 80 endpos[i]=fin; 81 } 82 for(int i=1;i<=siz;i++) 83 has[s[i].len]++; 84 for(int i=1;i<=siz;i++) 85 has[i]+=has[i-1]; 86 for(int i=1;i<=siz;i++) 87 topo[has[s[i].len]--]=i; 88 for(int i=siz;i;i--) 89 { 90 int x=topo[i]; 91 p[s[x].pre].wgt+=p[x].wgt; 92 } 93 for(int i=1;i<=siz;i++) 94 { 95 int x=topo[i]; 96 p[x].fa[0]=s[x].pre; 97 p[1].fa[0]=1; 98 for(int j=1;j<=16;j++) 99 p[x].fa[j]=p[p[x].fa[j-1]].fa[j-1]; 100 } 101 int tmpl=0; 102 str[++tmpl]='*'; 103 for(int i=1;i<=len;i++) 104 { 105 str[++tmpl]='#'; 106 str[++tmpl]=tmp[i]; 107 pos[tmpl]=i; 108 } 109 str[++tmpl]='#'; 110 str[++tmpl]='$'; 111 int now=0; 112 for(int i=1;i<=tmpl;i++) 113 { 114 f[i]=std::min(f[now]+now-i,f[now*2-i]); 115 f[i]=std::max(f[i],1); 116 check(pos[i-f[i]+2],pos[i+f[i]-2]); 117 while(str[i-f[i]]==str[i+f[i]]) 118 { 119 f[i]++; 120 check(pos[i-f[i]+2],pos[i+f[i]-2]); 121 } 122 if(f[now]+now<f[i]+i) 123 now=i; 124 } 125 printf("%lld\n",ans); 126 return 0; 127 }
2.PAM模板
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 typedef long long lnt; 5 struct pant{ 6 int tranc[26]; 7 int pre; 8 int len; 9 int wgt; 10 }; 11 namespace PAM{ 12 pant h[1000000]; 13 int siz; 14 int fin; 15 void Res(void) 16 { 17 fin=0; 18 siz=1; 19 h[0].pre=h[1].pre=1; 20 h[1].len=-1; 21 return ; 22 } 23 bool mismatch(char *a,int i,int pa) 24 { 25 return a[i-h[pa].len-1]!=a[i]; 26 } 27 void Insert(char *a,int i) 28 { 29 int nwp,lsp,mac; 30 lsp=fin; 31 int c=a[i]-'a'; 32 while(mismatch(a,i,lsp)) 33 lsp=h[lsp].pre; 34 if(!h[lsp].tranc[c]) 35 { 36 nwp=++siz; 37 mac=h[lsp].pre; 38 h[nwp].len=h[lsp].len+2; 39 while(mismatch(a,i,mac)) 40 mac=h[mac].pre; 41 h[nwp].pre=h[mac].tranc[c]; 42 h[lsp].tranc[c]=nwp; 43 } 44 fin=h[lsp].tranc[c]; 45 h[fin].wgt++; 46 return ; 47 } 48 lnt build(void) 49 { 50 lnt ans=0; 51 for(int i=siz;i;i--) 52 { 53 h[h[i].pre].wgt+=h[i].wgt; 54 ans=std::max(ans,(lnt)(h[i].len)*(lnt)(h[i].wgt)); 55 } 56 return ans; 57 } 58 } 59 char tmp[1000000]; 60 int main() 61 { 62 PAM::Res(); 63 scanf("%s",tmp+1); 64 int len=strlen(tmp+1); 65 for(int i=1;i<=len;i++) 66 PAM::Insert(tmp,i); 67 printf("%lld\n",PAM::build()); 68 return 0; 69 }