初见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 }