将原串复制放到后面之后就是用后缀数组排序的裸题了,后缀数组部分见笔记。。
#include<iostream>
#include<cstdio>
#include<memory.h>
#define N 300005
using namespace std;
int i,n,sa[N],rank[N],buc[N],sec[N],key[N],r2[N];//buc为桶,sec为基数排序时第二关键字的升序序列
char s[N],ans[N];
bool cmp(int x,int y,int d){return r2[x]==r2[y]&&r2[x+d]==r2[y+d];}
void getsa()
{
int i,j,d=1,p=0;
for (i=0;i<n;i++) buc[i]=0;
for (i=0;i<n;i++) buc[rank[i]=(int)s[i]]++;
for (i=1;i<=256;i++) buc[i]+=buc[i-1];
for (i=n-1;i>=0;i--) sa[--buc[rank[i]]]=i;
while (d<n)
{
for (p=0,i=n-d;i<n;i++) sec[p++]=i;
for (i=0;i<n;i++) if (sa[i]>=d) sec[p++]=sa[i]-d;
for (i=0;i<n;i++) buc[i]=0,r2[i]=rank[i];
for (i=0;i<n;i++) buc[key[i]=rank[sec[i]]]++;
for (i=1;i<n;i++) buc[i]+=buc[i-1];
for (i=n-1;i>=0;i--) sa[--buc[key[i]]]=sec[i];
for (rank[sa[0]]=0,p=0,i=1;i<n;i++)
rank[sa[i]]=cmp(sa[i-1],sa[i],d)? p:++p;
d*=2;
}
}
int main()
{
freopen("sa.in","r",stdin);
scanf("%s",s);
n=strlen(s);
for (i=n;i<2*n;i++) s[i]=s[i-n];
n=2*n;
getsa();
for (i=0;i<n;i++) if (sa[i]<n/2) printf("%c",s[sa[i]+n/2-1]);
}