題意:求連續重複次數最多的子串ios
一個連續重複子串能夠描述爲\(l,r,len\)(端點,循環節長度)git
\(O(n^2)\):直接枚舉\(l,len\),而後求\(l\)和\(l+len\)的\(LCP\),就能獲得最大的\(r\)數組
考慮不一一枚舉\(l\)spa
枚舉\(len\)以後,從一個點開始向前取\(LCP\),向後取\(LCP\),就可以拼出一個完整的循環串code
用這種方法能夠去掉大量重複枚舉,只枚舉\(l=k\cdot len (k\in Z)\)get
用ST表查詢能夠作到\(O(n \ln n)\)string
細節彷佛蠻多的,代碼很煩it
#include<cstdio> #include<algorithm> #include<iostream> #include<cctype> #include<cstring> #include<cassert> using namespace std; namespace Folder{ #define reg register #define pb push_back typedef long long ll; typedef unsigned long long ull; #define rep(i,a,b) for(reg int i=a,i##end=b;i<=i##end;++i) #define drep(i,a,b) for(reg int i=a,i##end=b;i>=i##end;--i) template <class T> inline void cmin(T &a,T b){ ((a>b)&&(a=b)); } template <class T> inline void cmax(T &a,T b){ ((a<b)&&(a=b)); } char IO; //template <class T=int> int rd(){ int s=0; int f=0; while(!isdigit(IO=getchar())) f|=(IO=='-'); do s=(s<<1)+(s<<3)+(IO^'0'); while(isdigit(IO=getchar())); return f?-s:s; } } using namespace Folder; const int N=1e5+10,INF=1e9; int n; char s[N]; int kase; #define ms(a) memset(a,0,sizeof a) struct Sparse_Table{ int s[20][N],Log[N]; void PreMake(const int *a){ rep(i,2,n) Log[i]=Log[i>>1]+1; rep(i,1,n) s[0][i]=a[i]; rep(i,1,Log[n]) { int len=(1<<(i-1)); rep(j,1,n-(1<<i)+1) s[i][j]=min(s[i-1][j],s[i-1][j+len]); } } int Que(int l,int r) { int d=Log[r-l+1]; return min(s[d][l],s[d][r-(1<<d)+1]); } }; struct Suffix_Array{ int cnt[N],rk[N<<1],sa[N],tmp[N],lcp[N]; Sparse_Table ST; void PreMake(char *s){ n=strlen(s+1); memset(cnt,0,800); rep(i,1,n) cnt[(int)s[i]]++; rep(i,1,200) cnt[i]+=cnt[i-1]; rep(i,1,n) rk[i]=cnt[(int)s[i]],sa[i]=i; rep(i,n+1,n*2) rk[i]=0; for(reg int k=1;k<=n;k<<=1) { rep(i,0,n) cnt[i]=0; rep(i,1,n) cnt[rk[i+k]]++; rep(i,1,n) cnt[i]+=cnt[i-1]; drep(i,n,1) tmp[cnt[rk[i+k]]--]=i; rep(i,0,n) cnt[i]=0; rep(i,1,n) cnt[rk[i]]++; rep(i,1,n) cnt[i]+=cnt[i-1]; drep(i,n,1) sa[cnt[rk[tmp[i]]]--]=tmp[i]; rep(i,1,n) tmp[sa[i]]=tmp[sa[i-1]]+(rk[sa[i]]!=rk[sa[i-1]]||rk[sa[i]+k]!=rk[sa[i-1]+k]); rep(i,1,n) rk[i]=tmp[i]; } int h=0; memset(lcp,0,(n+2)*4); rep(i,1,n) { int j=sa[rk[i]-1]; if(h) h--; while(i+h<=n && j+h<=n && s[i+h]==s[j+h]) h++; lcp[rk[i]-1]=h; } ST.PreMake(lcp); } int Que(int x,int y){ if(x==y) return n-x+1; if(rk[x]>rk[y]) swap(x,y); return ST.Que(rk[x],rk[y]-1); } }SA,RSA; Sparse_Table ST; int main(){ while(~scanf("%s",s+1) && s[1]!='#') { n=strlen(s+1); SA.PreMake(s),reverse(s+1,s+n+1),RSA.PreMake(s); ST.PreMake(SA.rk); int ans=0,st,ed; rep(i,1,n) { rep(j,1,n) { int a=i*(j-1)+1,b=i*j+1; if(b>n) break; int len=SA.Que(a,b)+RSA.Que(n-a+1,n-b+1)-1; // 向前和向後找LCP if(len<0) continue; if(len<i) continue; int l=a-RSA.Que(n-a+1,n-b+1)+1,r=b+SA.Que(a,b)-1; int p=SA.sa[ST.Que(l,r-(len/i+1)*i+1)]; l=p,r=p+(len/i+1)*i-1; if(len/i+1>ans) ans=len/i+1,st=l,ed=r; else if(len/i+1==ans && (SA.rk[st]>SA.rk[l]||(SA.rk[st]==SA.rk[l]&& r-l+1<ed-st+1) ) ) st=l,ed=r; } } if(!ans) ans=1,st=SA.sa[1],ed=SA.sa[1]; reverse(s+1,s+n+1); printf("Case %d: ",++kase); rep(i,st,ed) putchar(s[i]); putchar('\n'); } }