(后缀数组模板)BZOJ1031-[JSOI2007]字符加密Cipher

BZOJ1031-[JSOI2007]字符加密Cipher

  题意:

    

  题解:

    这道题约等于后缀数组的模板题了.把字符串复制一份接在原字符串的尾部,形成一个新字符串.对这个字符串进行后缀排序,前一半的排名就是按题意排序后的结果.

    第一次写后缀数组,有很多细节要注意,也调了好久,代码里面基本上是一行一个for循环,差点被搞炸.

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=400000;
char s[N+10];
int n,ch_sz=200,sa[N+10],rk[N+10],c[N+10],sa2[N+10],p;
void sort_suffix(){
    for(int i=1;i<=n;++i) ++c[rk[i]=s[i]];
    for(int i=1;i<=ch_sz;++i) c[i]+=c[i-1];
    for(int i=n;i>=1;--i) sa[c[rk[i]]--]=i;
    for(int i=1;i<=n;i*=2){
        p=0;
        for(int j=n-i+1;j<=n;++j) sa2[++p]=j;
        for(int j=1;j<=n;++j) if(sa[j]>i) sa2[++p]=sa[j]-i;
        for(int j=1;j<=ch_sz;++j) c[j]=0;
        for(int j=1;j<=n;++j) ++c[rk[sa2[j]]];
        for(int j=1;j<=ch_sz;++j) c[j]+=c[j-1];
        for(int j=n;j>=1;--j) sa[c[rk[sa2[j]]]--]=sa2[j];
        swap(rk,sa2); rk[sa[1]]=ch_sz=1;
        for(int j=2;j<=n;++j)
            rk[sa[j]]=sa2[sa[j]]==sa2[sa[j-1]]&&sa2[sa[j]+i]==sa2[sa[j-1]+i]?ch_sz:++ch_sz;
        if(ch_sz==n) break;
    }
}
int main(){
    scanf("%s",s+1); n=strlen(s+1);
    for(int i=n+1;i<=n*2;++i) s[i]=s[i-n];
    n<<=1;
    sort_suffix();
    for(int i=1;i<=n;++i) if(sa[i]<=n/2) printf("%c",s[sa[i]+n/2-1]);
    return 0;
}

 

posted @ 2017-09-21 20:45  jxcakak  阅读(111)  评论(0编辑  收藏  举报