bzoj 1031: [JSOI2007]字符加密Cipher

题目链接

bzoj 1031: [JSOI2007]字符加密Cipher

后缀数组裸题。
把字符串接到自己后面后直接排序。
输出结尾字符就好了QAQ

/**************************************************************
    Problem: 1031
    Language: C++
    Result: Accepted
    Time:1588 ms
    Memory:21328 kb
****************************************************************/
 
#include<cstdio>
#include<cstring>
#include<algorithm>
const int maxn = 1000007;
int saf[maxn],sa[maxn],rank[maxn],cnt[maxn],s[maxn];
char a[maxn];
int n,m,st;
inline void rsort() {
    for(int i=0;i<=m;++i) cnt[i]=0;
    for(int i=1;i<=n;++i) cnt[rank[saf[i]]]++;
    for(int i=1;i<=m;++i) cnt[i]+=cnt[i-1];
    for(int i=n;i>=1;--i) sa[cnt[rank[saf[i]]]--]=saf[i];
}
inline bool cmp(int *f,int x,int y,int w) {
    return f[x]==f[y]&&f[x+w]==f[y+w];
}
void get_sa() {
    for(int i=1;i<=n;++i) rank[i]=s[i],saf[i]=i;m=125;
    rsort();
    for(int p=0,w=1;p<n;w<<=1,m=p) {
        p=0;
        for(int i=n-w+1;i<=n;++i) saf[++p]=i;
        for(int i=1;i<=n;++i) 
            if(sa[i]>w) saf[++p]=sa[i]-w;
        rsort();
        std::swap(rank,saf);rank[sa[1]]=p=1;
        for(int i=2;i<=n;++i) rank[sa[i]]=cmp(saf,sa[i],sa[i-1],w)? p:++p;
    }
    for(int i=1;i<=n;++i) if(sa[i]<=st)printf("%c",a[sa[i]+st-1]);
}
int main() {
    scanf("%s",a+1);
    st=n=strlen(a+1);
    for(int i=1;i<n;++i)a[i+n]=a[i];
    n=n*2-1;
    for(int i=1;i<=n;++i) s[i]=a[i],s[i+n]=s[i];
    s[0]=s[n+1]=-1; 
    get_sa();
    return 0;
}
原文地址:https://www.cnblogs.com/sssy/p/8420767.html