1. 程式人生 > >解題:APIO 2014 迴文串

解題:APIO 2014 迴文串

題面

初見SAM

洛谷資料太弱了,我SAM寫錯了居然有90pts=。=???

SAM求一個子串$(l,r)$的出現次數:從右端點對應狀態開始在parent樹上倍增,當目標節點的$len$大於等於子串長度時就往上跳,最後所在節點的$len$就是該串的出現次數

於是邊$manacher$邊在SAM上統計當前串的出現次數即可,複雜度$O(n\log 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