http://www.lydsy.com/JudgeOnline/problem.php?id=2882
将串S复制一遍变成SS
对SS构建后缀自动机,在上面走标号最小的边len(S)步,即可得最小循环串
因为后缀自动机可以识别串的所有后缀
而S的最小循环串一定是SS后缀的前缀
#include<map> #include<cstdio> #include<iostream> using namespace std; #define N 600001 int a[N]; map<int,int>ch[N<<1]; int tot=1,fa[N<<1],len[N<<1]; int last=1,p,q,np,nq; void read(int &x) { x=0; char c=getchar(); while(!isdigit(c)) c=getchar(); while(isdigit(c)) { x=x*10+c-'0'; c=getchar(); } } void extend(int c) { len[np=++tot]=len[last]+1; for(p=last;p && ch[p].find(c)==ch[p].end();p=fa[p]) ch[p][c]=np; if(!p) fa[np]=1; else { q=ch[p][c]; if(len[q]==len[p]+1) fa[np]=q; else { len[nq=++tot]=len[p]+1; ch[nq]=ch[q]; fa[nq]=fa[q]; fa[q]=fa[np]=nq; for(;ch[p][c]==q;p=fa[p]) ch[p][c]=nq; } } last=np; } int main() { int n,x; read(n); for(int i=1;i<=n;++i) { read(x); extend(x); a[i]=x; } for(int i=1;i<=n;++i) extend(a[i]); map<int,int>::iterator it; int now=1; for(int i=1;i<=n;++i) { if(i>1) putchar(' '); it=ch[now].begin(); printf("%d",it->first); now=ch[now][it->first]; } }