后缀自动机裸题
将序列复制两遍建后缀自动机
每次贪心地走最小的边
走N次得到答案
#include <cstdio>
#include <cstring>
#include <string>
#include <iostream>
#include <map>
#define N 1000010
using namespace std;
struct SAM_{
int fail[N],stp[N],p,cnt;
map<int,int> next[N];
SAM_(){p=cnt=1;}
void Extend(int x){
int np=++cnt;stp[np]=stp[p]+1;
while(p&&!next[p].count(x)) next[p][x]=np,p=fail[p];
if(!p) fail[np]=1;
else{
int q=next[p][x];
if(stp[q]==stp[p]+1) fail[np]=q;
else{
int nq=++cnt;stp[nq]=stp[q]+1;
next[nq]=next[q];
fail[nq]=fail[q];
fail[q]=fail[np]=nq;
while(p&&next[p][x]==q) next[p][x]=nq,p=fail[p];
}
}
p=np;
}
void Explorer(int n){
p=1;
for(int i=1;i<=n;i++){
printf("%d",next[p].begin()->first);
p=next[p].begin()->second;
if(i!=n)putchar(' ');else putchar('\n');
}
}
}SAM;
int n,A[N];
inline void reaD(int &x){
char Ch=getchar();x=0;
for(;Ch>'9'||Ch<'0';Ch=getchar());
for(;Ch>='0'&&Ch<='9';x=x*10+Ch-'0',Ch=getchar());
}
int main(){
reaD(n);
for(int i=1;i<=n;i++) reaD(A[i]);
for(int i=1;i<=n;i++) SAM.Extend(A[i]);
for(int i=1;i<=n;i++) SAM.Extend(A[i]);
return SAM.Explorer(n),0;
}