Description
求字符串的最小循环表示.
Sol
SAM.
把原串复制一遍,建出SAM,然后每次选最小的一个跑 \(len\) 次,这就是最小循环表示的最后一个节点,然后 \(x-len+1\) 即为答案.
Code
#include<cstdio> #include<cstring> #include<iostream> using namespace std; const int N = 20005; int n,rt,lst,cnt,l; int s[N]; int val[N],par[N],go[N][26]; inline int in(int x=0,char ch=getchar()){ while(ch>‘9‘ || ch<‘0‘) ch=getchar(); while(ch>=‘0‘ && ch<=‘9‘) x=(x<<3)+(x<<1)+ch-‘0‘,ch=getchar();return x; } inline int read(int l=0,char ch=getchar()){ while(ch>‘z‘ || ch<‘a‘) ch=getchar(); while(ch>=‘a‘ && ch<=‘z‘) s[++l]=ch-‘a‘,ch=getchar();return l; } void Extend(int w){ int p=lst,np=++cnt;val[np]=val[p]+1,memset(go[np],0,sizeof(go[np])); while(p && !go[p][w]) go[p][w]=np,p=par[p]; if(!p) par[np]=rt; else{ int q=go[p][w]; if(val[p]+1 == val[q]) par[np]=q; else{ int nq=++cnt; val[nq]=val[p]+1; memcpy(go[nq],go[q],sizeof(go[q])); par[nq]=par[q]; par[np]=par[q]=nq; while(p && go[p][w]==q) go[p][w]=nq,p=par[p]; } }lst=np; } int work(){ int x=rt; for(int i=1;i<=l;i++) for(int j=0;j<26;j++) if(go[x][j]){ x=go[x][j];break; } return val[x]>=l?val[x]-l:val[x]; } int main(){ n=in(); for(int i=1;i<=n;i++){ l=read(),rt=lst=cnt=1; val[rt]=par[rt]=0;memset(go[rt],0,sizeof(go[rt])); for(int i=l+1;i<=2*l;i++) s[i]=s[i-l]; for(int i=1;i<=2*l;i++) Extend(s[i]); cout<<work()+1<<endl; } }
时间: 2024-11-10 07:14:48