解题:APIO 2014 回文串

题面

初见SAM

洛谷数据太弱了,我SAM写错了居然有90pts=。=???

SAM求一个子串$(l,r)$的出现次数:从右端点对应状态开始在parent树上倍增,当目标节点的$len$大于等于子串长度时就往上跳,最后所在节点的$len$就是该串的出现次数

于是边$manacher$边在SAM上统计当前串的出现次数即可,复杂度$O(nlog n)$,注意边界

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;
 5 const int N=600060,K=20;
 6 int p[N],noww[N],goal[N];
 7 int rnk[N],bkt[N],mul[N][K];
 8 int trs[N][26],fth[N],len[N],siz[N],num[N];
 9 char str[N>>1],Str[N]; 
10 int lth,lst,cnt,tot,mid,maxr;
11 long long ans;
12 void link(int f,int t)
13 {
14     noww[++cnt]=p[f];
15     goal[cnt]=t,p[f]=cnt;
16 }
17 void DFS(int nde,int fth)
18 {
19     mul[nde][0]=fth;
20     for(int i=p[nde];i;i=noww[i]) 
21         DFS(goal[i],nde),siz[nde]+=siz[goal[i]];
22     for(int i=1;mul[nde][i];i++)
23         mul[nde][i]=mul[mul[nde][i-1]][i-1];
24 }
25 void Insert(int ch,int ps)
26 {
27     int nde=lst,newn=++tot; 
28     num[ps]=lst=newn,siz[newn]=1,len[newn]=len[nde]+1;
29     while(nde&&!trs[nde][ch])
30         trs[nde][ch]=newn,nde=fth[nde];
31     if(!nde) fth[newn]=1;
32     else
33     {
34         int tran=trs[nde][ch];
35         if(len[tran]==len[nde]+1)
36             fth[newn]=tran;
37         else
38         {
39             int rnde=++tot; len[rnde]=len[nde]+1;
40             for(int i=0;i<=25;i++) trs[rnde][i]=trs[tran][i];
41             fth[rnde]=fth[tran],fth[tran]=fth[newn]=rnde;
42             while(nde&&trs[nde][ch]==tran)
43                 trs[nde][ch]=rnde,nde=fth[nde];
44         }
45     }
46 }
47 void prework()
48 {
49     register int i,j;
50     scanf("%s",str+1),lth=strlen(str+1),lst=tot=1;
51     for(i=1;i<=lth;i++) Insert(str[i]-'a',i);
52     for(i=1;i<=tot;i++) link(fth[i],i); DFS(1,0);
53 }
54 void Solve(int l,int r)
55 {
56     l=(l+l%2)/2,r=(r-r%2)/2; 
57     if(l>r) return ;
58     int nde=num[r],lth=r-l+1;
59     for(int i=19;~i;i--)
60         if(lth<=len[mul[nde][i]])
61             nde=mul[nde][i];
62     ans=max(ans,1ll*lth*siz[nde]);
63 }
64 void Manacher()
65 {
66     register int i;
67     int newl=2*lth+1;
68     for(i=1;i<=newl;i++)
69         Str[i]=(i&1)?'?':str[i>>1];
70     Str[0]='>',Str[newl+1]='<';
71     for(i=1;i<=newl;i++)
72     {
73         fth[i]=(maxr>=i)?min(maxr-i+1,fth[2*mid-i]):1;
74         Solve(i-fth[i]+1,i+fth[i]-1);
75         while(Str[i-fth[i]]==Str[i+fth[i]]) 
76             fth[i]++,Solve(i-fth[i]+1,i+fth[i]-1);
77         if(i+fth[i]-1>maxr) maxr=i+fth[i]-1,mid=i;
78     }
79 }
80 int main()
81 {
82     prework(),Manacher();
83     printf("%lld",ans);
84     return 0;
85 }
View Code
原文地址:https://www.cnblogs.com/ydnhaha/p/10116400.html