#后缀数组#洛谷 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;
}
posted @ 2020-10-03 02:42  lemondinosaur  阅读(78)  评论(0编辑  收藏  举报