BZOJ 3676: [Apio2014]回文串 后缀自动机 Manacher 倍增
http://www.lydsy.com/JudgeOnline/problem.php?id=3676
过程很艰难了,第一次提交Manacher忘了更新p数组,超时,第二次是倍增的第0维直接在自动机里完成,但是忽略了增加新点时fa变动的情况,还是肉眼查错最管用。
得到的教训是既然倍增就在倍增的函数里完成,自动机就在自动机里完成,不要随便乱搞赋值。
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<cstring> 5 #include<cmath> 6 #include<map> 7 using namespace std; 8 const int maxn=300010; 9 char ch[maxn]={}; 10 char ch1[maxn*2]={}; 11 int siz,siz1; 12 struct sam{ 13 int sig[26]; 14 int f,len,d[21],num; 15 }t[maxn*2]; 16 int tot=1,la=1; 17 int loc[maxn]={},cnt[maxn*2]={},b[maxn*2]={},p[maxn*2]={}; 18 long long ans=0; 19 void add(int z){ 20 int x=++tot,i=la; 21 t[x].len=t[la].len+1; 22 for(;i&&!t[i].sig[z];i=t[i].f) 23 t[i].sig[z]=x; 24 if(!i)t[x].f=1; 25 else{ 26 int p=t[i].sig[z]; 27 if(t[p].len==t[i].len+1)t[x].f=p; 28 else{ 29 int y=++tot; 30 t[y]=t[p];t[y].len=t[i].len+1; 31 t[p].f=t[x].f=y; 32 for(;i&&t[i].sig[z]==p;i=t[i].f) 33 t[i].sig[z]=y; 34 } 35 } 36 la=x; 37 } 38 void pre(){ 39 int z; 40 for(int i=1;i<=tot;i++)cnt[t[i].len]++; 41 for(int i=1;i<=siz;i++)cnt[i]+=cnt[i-1]; 42 for(int i=tot;i;i--)b[cnt[t[i].len]--]=i; 43 for(int i=1;i<=siz;i++)t[loc[i]].num=1; 44 for(int i=tot;i;i--){ 45 z=b[i];t[t[z].f].num+=t[z].num; 46 } 47 for(int i=1;i<=tot;i++){ 48 z=b[i];t[z].d[0]=t[z].f; 49 for(int j=1;j<=20;j++) 50 t[z].d[j]=t[t[z].d[j-1]].d[j-1]; 51 } 52 } 53 void getit(int l,int r){ 54 r=r/2;l=(l+1)/2; 55 if(r<l)return; 56 int z=loc[r]; 57 for(int i=20;i>-1;i--){ 58 if(t[t[z].d[i]].len>=r-l+1){ 59 z=t[z].d[i]; 60 } 61 } 62 long long sum=(long long)t[z].num*(r-l+1); 63 if(ans<sum)ans=sum; 64 } 65 void Manacher(){ 66 for(int i=1;i<=siz;i++)ch1[i*2]=ch[i],ch1[i*2-1]='#'; 67 ch1[siz*2+1]='#';ch1[siz*2+2]='\0';ch1[0]='$'; 68 siz1=siz*2+1; 69 int mx=0,id=0; 70 for(int i=1;i<=siz1;i++){ 71 if(mx>=i)p[i]=min(mx-i,p[id*2-i]); 72 else p[i]=0; 73 while(ch1[i+p[i]]==ch1[i-p[i]]){++p[i];getit(i-p[i]+1,i+p[i]-1);} 74 if(mx<i+p[i]){mx=i+p[i];id=i;} 75 } 76 } 77 int main(){ 78 memset(t,0,sizeof(t)); 79 scanf("%s",ch+1);siz=strlen(ch+1); 80 for(int i=1;i<=siz;i++){loc[i]=tot+1;add(ch[i]-'a');} 81 pre(); 82 Manacher(); 83 printf("%lld\n",ans); 84 return 0; 85 }