bzoj1031: [JSOI2007]字符加密Cipher(后缀数组)

来源:互联网 发布:java导入进度条 编辑:程序博客网 时间:2024/06/06 18:15

题目传送门
题目挺不错的。
赤果果的后缀数组啊。
我好像只会后缀数组作后缀排名了。
真的菜。(我要变强!!)

因为他的字符串排成了一圈了。所以说我们应该长度为两倍才行。
比如:
abcd。
那么就会有四个串。
abcd,bcda,cdab,dabc。
这样很容易就可以看出我们应该把字符串变成:
abcdabc。
这样的话我们就会有这四个串了。

那么拿新的字符串去跑一遍后缀数组。
那么就会有2*len-1个后缀。len表示原串长度
那么有些字符串很明显要越界了。
所以我们只要不越界的字符串输出最后一个字符就OK了。
比如这个后缀的初始位置为i。
因为每个串的长度都应该为len。
那么我们就要判断i+len-1也就是这个串的结束位置是否越界(<=2*len-1)

然后把最后一个字符都输出出来就OK了吧。

代码实现:

#include<cstdio>#include<cstring>using namespace std;char s[1100000];int sa1[1100000],sa2[1100000],Rsort[1100000],Rank[1100000],a[1100000],tt[1100000];char ans[1110000];void solve(int n,int m) {    for(int i=1;i<=n;i++)         Rank[i]=a[i];    memset(Rsort,0,sizeof(Rsort));    for(int i=1;i<=n;i++)         Rsort[Rank[i]]++;    for(int i=1;i<=m;i++)         Rsort[i]+=Rsort[i-1];    for(int i=n;i>=1;i--)         sa1[Rsort[Rank[i]]--]=i;    int p=0,ln=1;    while(p<n) {        int k=0;        for(int i=n-ln+1;i<=n;i++)             sa2[++k]=i;        for(int i=1;i<=n;i++)             if(sa1[i]-ln>0) sa2[++k]=sa1[i]-ln;        memset(Rsort,0,sizeof(Rsort));        for(int i=1;i<=n;i++)             Rsort[Rank[i]]++;        for(int i=1;i<=m;i++)             Rsort[i]+=Rsort[i-1];        for(int i=n;i>=1;i--)             sa1[Rsort[Rank[sa2[i]]]--]=sa2[i];        for(int i=1;i<=n;i++)             tt[i]=Rank[i];        p=1;        Rank[sa1[1]]=1;        for(int i=2;i<=n;i++) {            if(tt[sa1[i]]!=tt[sa1[i-1]] || tt[sa1[i]+ln]!=tt[sa1[i-1]+ln])                 p++;            Rank[sa1[i]]=p;        }        m=p;        ln*=2;    }    int len=0;    for(int i=1;i<=n;i++)         if(sa1[i]+n/2<=n)        //这里本来写的是sa1[i]+n/2+1-1的,因为2*len-1很明显为基数,那么他除以2的话就会比原长度少1,那么要加上1,后面的-1就是加上长度之后-1的位置就是结尾。            ans[++len]=s[sa1[i]+n/2];    for(int i=1;i<=len;i++)        printf("%c",ans[i]);    printf("\n");}int main() {    scanf("%s",s+1);    int len=strlen(s+1);    for(int i=1;i<=len-1;i++)  //把字符串复制一遍        s[i+len]=s[i];    len*=2;len--;    for(int i=1;i<=len;i++)         a[i]=s[i];    solve(len,300);    return 0;}

后缀数组有点玄学,初二的时候第一次学很懵13。
然而现在终于理解了,太开心了!

阅读全文
0 0
原创粉丝点击