BZOJ 2342 [SHOI2011]双倍回文 (回文自动机)

题目大意:略

先建出$PAM$

因为双倍回文串一定是4的倍数,所以找出$PAM$里所有$dep$能整除4的节点

看这个串是否存在一个回文后缀,长度恰好为它的一半,沿着$pre$链往上跳就行了

暴跳可能会$T$,所以倍增了跳

如果被卡空间,可以把trs数组当成倍增数组

 1 #include <cmath>
 2 #include <vector>
 3 #include <cstdio>
 4 #include <cstring>
 5 #include <algorithm>
 6 #define N1 500100
 7 #define S1 (N1<<1)
 8 #define ll long long
 9 #define uint unsigned int
10 #define rint register int 
11 #define dd double
12 #define il inline 
13 #define inf 0x3f3f3f3f
14 #define idx(X) (X-'a')
15 using namespace std;
16 
17 int gint()
18 {
19     int ret=0,fh=1;char c=getchar();
20     while(c<'0'||c>'9'){if(c=='-')fh=-1;c=getchar();}
21     while(c>='0'&&c<='9'){ret=ret*10+c-'0';c=getchar();}
22     return ret*fh;
23 }
24 int len;
25 namespace PAM{
26 int trs[N1][26],pre[N1],dep[N1],la,tot;
27 void init(){la=tot=1,pre[0]=pre[1]=1,dep[1]=-1;}
28 int chk(char *str,int i,int p){return str[i-dep[p]-1]!=str[i]?1:0;}
29 void insert(char *str,int i)
30 {
31     int p=la,np,fp,c=idx(str[i]);
32     while(chk(str,i,p)) p=pre[p];
33     if(!trs[p][c])
34     {
35         np=++tot;
36         dep[np]=dep[p]+2;
37         fp=pre[p];
38         while(chk(str,i,fp)) fp=pre[fp];
39         pre[np]=trs[fp][c];
40         trs[p][c]=np;
41     }
42     la=trs[p][c];
43 }
44 int multi()
45 {
46     int ans=0,i,j,x;
47     trs[1][0]=trs[1][1]=0;
48     trs[0][0]=trs[0][1]=0;
49     for(i=2;i<=tot;i++) trs[i][0]=i,trs[i][1]=pre[i];
50     for(j=2;j<=20;j++)
51         for(int i=2;i<=tot;i++)
52         trs[i][j]=trs[ trs[i][j-1] ][j-1];
53     for(i=2;i<=tot;i++)
54         if(dep[i]%4==0)
55         {
56             x=i;
57             for(j=20;j>=0;j--)
58                 if(dep[trs[x][j]]>=dep[i]/2) x=trs[x][j];
59             if(dep[x]!=dep[i]/2) continue;
60             ans=max(ans,dep[i]);
61         }
62     return ans;
63 }
64 };
65 char str[N1];
66 
67 int main()
68 {
69     //freopen("t2.in","r",stdin);
70     //freopen("a.out","w",stdout);
71     scanf("%d",&len);
72     scanf("%s",str+1);
73     PAM::init();
74     for(int i=1;i<=len;i++) PAM::insert(str,i);
75     printf("%d\n",PAM::multi());
76     return 0;
77 }

 

posted @ 2018-12-19 12:52  guapisolo  阅读(206)  评论(0编辑  收藏  举报