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 }
View Code

 

 

posted @ 2018-03-15 11:54  鲸头鹳  阅读(105)  评论(0编辑  收藏  举报