题目描述
题解
把串重复一遍然后建立后缀自动机
从头找一个最小的输出就行了
注意字符集非常大需要用map,然后可以用一个迭代器来找
其实这道题正确的姿势应该是最小表示法
具体的可以看WC2003周源的课件
代码
#include<iostream>
#include<cstring>
#include<cstdio>
#include<map>
using namespace std;
#define N 1500005
int s[N];
int n,root,last,sz,p,np,q,nq;
int pre[N],step[N];
map <int,int> ch[N];
void extend()
{
for (int i=1;i<=2*n;++i)
{
int x=s[i];
p=last;np=++sz;last=np;
step[np]=step[p]+1;
while (p&&!ch[p][x])
{
ch[p][x]=np;
p=pre[p];
}
if (!p) pre[np]=root;
else
{
q=ch[p][x];
if (step[q]==step[p]+1) pre[np]=q;
else
{
nq=++sz;
step[nq]=step[p]+1;
ch[nq]=ch[q];
pre[nq]=pre[q];
pre[np]=pre[q]=nq;
while (ch[p][x]==q)
{
ch[p][x]=nq;
p=pre[p];
}
}
}
}
}
void sam()
{
p=root;
map<int,int>::iterator t;
for (int i=1;i<=n;++i)
{
t=ch[p].begin();
p=t->second;
if (i!=n) printf("%d ",t->first);
else printf("%d\n",t->first);
}
}
int main()
{
scanf("%d",&n);
for (int i=1;i<=n;++i) scanf("%d",&s[i]),s[n+i]=s[i];
root=last=++sz;
extend();
sam();
}
#include<iostream>
#include<cstring>
#include<cstdio>
#include<map>
using namespace std;
#define N 600005
int n;
int s[N];
int mr()
{
int i=1,j=2;
while (i<=n&&j<=n)
{
int k=0;
while (s[i+k]==s[j+k]&&k<=n) ++k;
if (k==n+1) break;
if (s[i+k]>s[j+k]) i=i+k+1;
else j=j+k+1;
if (i==j) ++j;
}
return min(i,j);
}
int main()
{
scanf("%d",&n);
for (int i=1;i<=n;++i) scanf("%d",&s[i]),s[n+i]=s[i];
int loc=mr();
for (int i=loc;i<=loc+n-1;++i)
printf("%d%c",s[i]," \n"[i==loc+n-1]);
}