#后缀数组#洛谷 4051 [JSOI2007]字符加密
分析
将字符串复制一份放入末尾,将其后缀排序之后
SA数组既然表示排名为\(i\)的后缀的起始位置,
那么只要它在\([1,len]\)范围内就是合法的,
那么输出以这个位置开头长度为\(len\)的末位置的字母就可以了
代码
#include <cstdio>
#include <cctype>
#include <cstring>
#include <algorithm>
#define rr register
using namespace std;
const int N=200011;
char s[N]; int len;
struct Suffix_Array{
int C[N],sa[N],tp[N],rk[N],height[N],n,M;
inline void SSort(){
for (rr int i=0;i<=M;++i) C[i]=0;
for (rr int i=1;i<=n;++i) ++C[rk[tp[i]]];
for (rr int i=1;i<=M;++i) C[i]+=C[i-1];
for (rr int i=n;i;--i) sa[C[rk[tp[i]]]--]=tp[i];
}
inline void suffix(char *s,int tn,int tm){
n=tn,M=tm;
for (rr int i=1;i<=n;++i) rk[i]=s[i],tp[i]=i; SSort();
for (rr int len=1,p=1;p<n;M=p,len<<=1){
p=0;
for (rr int i=n-len+1;i<=n;++i) tp[++p]=i;
for (rr int i=1;i<=n;++i) if (sa[i]>len) tp[++p]=sa[i]-len;
SSort(),swap(tp,rk),rk[sa[1]]=p=1;
for (rr int i=2;i<=n;++i) rk[sa[i]]=(p+=tp[sa[i]]!=tp[sa[i-1]]||tp[sa[i]+len]!=tp[sa[i-1]+len]);
}
for (rr int i=1,k,j=0;i<=n;height[rk[i]]=j,++i)
for (j+=(!j)-1,k=sa[rk[i]-1];s[i+j]==s[j+k];++j);
}
}SA;
inline signed iut(){
rr int ans=0; rr char c=getchar();
while (!isdigit(c)) c=getchar();
while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
return ans;
}
inline void print(int ans){
if (ans>9) print(ans/10);
putchar(ans%10+48);
}
signed main(){
scanf("%s",s+1),len=strlen(s+1);
for (rr int i=1;i<=len;++i) s[len+i]=s[i];
SA.suffix(s,len<<1,128);
for (rr int i=1;i<=SA.n;++i)
if (SA.sa[i]<=len)
putchar(s[SA.sa[i]+len-1]);
return 0;
}