3676: [Apio2014]回文串
Time Limit: 20 Sec Memory Limit: 128 MB
Submit: 2343 Solved: 1031Description
考虑一个只包含小写拉丁字母的字符串s。我们定义s的一个子串t的“出
现值”为t在s中的出现次数乘以t的长度。请你求出s的所有回文子串中的最
大出现值。Input
输入只有一行,为一个只包含小写字母(a -z)的非空字符串s。
Output
输出一个整数,为逝查回文子串的最大出现值。Sample Input
【样例输入l】
abacaba
【样例输入2]
www
Sample Output
【样例输出l】
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。Source
【分析】
听说回文自动机可以秒掉这题,以后再学吧。
用串建SAM,然后求出right数组。
manacher告诉我们,本质不同的回文串最多n个,只有在mx变的时候可能增加一个回文串。
用manacher求出所有本质不同的回文串,然后在SAM上问。
那就是问[L,R]这个区间的子串出现了多少次【感觉这个用后缀数组的话是nlogn^2的
从SAM的pre边相当于AC自动机上的fail,形成一棵树,pre树上倍增即可。
就是从POS[R]开始跳,当他代表的子串的长度大于r-l+1,即可计入答案,当然子串长度越小越好(更有可能出现最多次)
【记得拓扑序
【啊。。。卡空间。。
1 #include<cstdio> 2 #include<cstdlib> 3 #include<cstring> 4 #include<iostream> 5 #include<algorithm> 6 using namespace std; 7 #define Maxn 301000 8 #define LL long long 9 10 // int mymax(int x,int y) {return x>y?x:y;} 11 LL mymax(LL x,LL y) {return x>y?x:y;} 12 int mymin(int x,int y) {return x<y?x:y;} 13 14 LL ans=0; 15 16 struct node 17 { 18 int pre,step,son[30],rt; 19 }t[2*Maxn];int last,tot; 20 int v[2*Maxn],q[2*Maxn],pos[2*Maxn]; 21 22 int ff[2*Maxn][19]; 23 void get_f() 24 { 25 for(int i=1;i<=tot;i++) ff[i][0]=t[i].pre; 26 for(int i=1;i<=tot;i++) 27 { 28 int nw=q[i]; 29 for(int j=1;j<=18;j++) 30 ff[nw][j]=ff[ff[nw][j-1]][j-1]; 31 } 32 } 33 34 int now; 35 struct sam 36 { 37 void extend(int k) 38 { 39 int np=++tot,p=last; 40 t[np].step=t[last].step+1; 41 t[np].rt=1;pos[++now]=np; 42 while(p&&!t[p].son[k]) 43 { 44 t[p].son[k]=np; 45 p=t[p].pre; 46 } 47 if(!p) t[np].pre=1; 48 else 49 { 50 int q=t[p].son[k]; 51 if(t[q].step==t[p].step+1) t[np].pre=q; 52 else 53 { 54 int nq=++tot; 55 memcpy(t[nq].son,t[q].son,sizeof(t[nq].son)); 56 t[nq].step=t[p].step+1; 57 t[nq].pre=t[q].pre; 58 t[q].pre=t[np].pre=nq; 59 while(p&&t[p].son[k]==q) 60 { 61 t[p].son[k]=nq; 62 p=t[p].pre; 63 } 64 } 65 } 66 last=np; 67 } 68 void init() 69 { 70 memset(v,0,sizeof(v)); 71 for(int i=1;i<=tot;i++) v[t[i].step]++; 72 for(int i=1;i<=tot;i++) v[i]+=v[i-1]; 73 for(int i=tot;i>=1;i--) q[v[t[i].step]--]=i; 74 75 for(int i=tot;i>=1;i--) 76 { 77 int nw=q[i]; 78 t[t[nw].pre].rt+=t[nw].rt; 79 } 80 } 81 void ffind(int l,int r) 82 { 83 l=l/2+1;r=(r+1)/2; 84 int x=pos[r]; 85 for(int i=18;i>=0;i--) 86 { 87 if(t[ff[x][i]].step>=r-l+1) x=ff[x][i]; 88 } 89 ans=mymax(ans,1LL*(r-l+1)*t[x].rt); 90 } 91 }sam; 92 93 char s[Maxn]; 94 // int a[2*Maxn],p[2*Maxn]; 95 96 void manacher(int l) 97 { 98 v[0]=99; 99 for(int i=0;i<l;i++) v[2*i+1]=s[i]-'a'+1,v[2*i+2]=99; 100 v[2*l+1]=110; 101 l=2*l; 102 int mx=0,id=0; 103 for(int i=1;i<=l;i++) 104 { 105 if(i<mx) q[i]=mymin(mx-i+1,q[2*id-i]); 106 else q[i]=1; 107 while(v[i+q[i]]==v[i-q[i]]&&i-q[i]>=0) 108 { 109 q[i]++; 110 sam.ffind(i-q[i]+1,i+q[i]-1); 111 } 112 if(i+q[i]-1>mx) mx=i+q[i]-1,id=i; 113 } 114 } 115 116 int main() 117 { 118 scanf("%s",s); 119 int l=strlen(s); 120 last=tot=1;now=0; 121 for(int i=0;i<l;i++) sam.extend(s[i]-'a'+1); 122 sam.init(); 123 get_f(); 124 manacher(l); 125 printf("%lld ",ans); 126 return 0; 127 }
2017-04-17 16:54:09