洛谷 P4051 [JSOI2007]字符加密 后缀数组

版权声明:2333 https://blog.csdn.net/liangzihao1/article/details/82219400

题目描述
喜欢钻研问题的JS同学,最近又迷上了对加密方法的思考。一天,他突然想出了一种他认为是终极的加密办法:把需要加密的信息排成一圈,显然,它们有很多种不同的读法。
这里写图片描述
例如‘JSOI07’,可以读作:
JSOI07 SOI07J OI07JS I07JSO 07JSOI 7JSOI0
把它们按照字符串的大小排序:
07JSOI 7JSOI0 I07JSO JSOI07 OI07JS SOI07J
读出最后一列字符:I0O7SJ,就是加密后的字符串(其实这个加密手段实在很容易破解,鉴于这是突然想出来的,那就^^)。 但是,如果想加密的字符串实在太长,你能写一个程序完成这个任务吗?

输入输出格式

输入格式:
输入文件包含一行,欲加密的字符串。注意字符串的内容不一定是字母、数字,也可以是符号等。

输出格式:
输出一行,为加密后的字符串。

输入输出样例

输入样例#1:
JSOI07
输出样例#1:
I0O7SJ
说明
对于40%的数据字符串的长度不超过10000。
对于100%的数据字符串的长度不超过100000。

分析:
把原串复制一遍到后面,然后进行后缀排序。
显然原来的一种读法相当于一个子串。两个子串如果不同,他们所代表后缀排序后和子串排序后没有区别;如果相同,则对答案影响也相同,所以正确性显然。

代码:

// luogu-judger-enable-o2
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>

const int maxn=2e5+7;

using namespace std;

char s[maxn],ans[maxn];
int sa[maxn],x[maxn],y[maxn],c[maxn];
int n,cnt;

void getsa()
{
    int m=1000;
    for (int i=0;i<=m;i++) c[i]=0;
    for (int i=0;i<n;i++) x[i]=s[i];
    for (int i=0;i<n;i++) c[x[i]]++;
    for (int i=1;i<=m;i++) c[i]+=c[i-1];
    for (int i=n-1;i>=0;i--) sa[--c[x[i]]]=i;
    for (int k=1;k<=n;k<<=1)
    {
        int num=0;
        for (int i=n-k;i<n;i++) y[num++]=i;
        for (int i=0;i<n;i++) if (sa[i]>=k) y[num++]=sa[i]-k;
        for (int i=0;i<=m;i++) c[i]=0;
        for (int i=0;i<n;i++) c[x[i]]++;
        for (int i=1;i<=m;i++) c[i]+=c[i-1];
        for (int i=n-1;i>=0;i--) sa[--c[x[y[i]]]]=y[i],y[i]=0;
        swap(x,y);
        num=1;
        x[sa[0]]=1;
        for (int i=1;i<n;i++)
        {
            if ((y[sa[i]]!=y[sa[i-1]]) || (y[sa[i]+k]!=y[sa[i-1]+k]))
            {
                x[sa[i]]=++num;
            }
            else x[sa[i]]=num;
        }
        if (num>=n) break;
        m=num;
    }
}

int main()
{
    scanf("%s",s);
    n=strlen(s);
    for (int i=0;i<n;i++) s[i+n]=s[i];
    n*=2;
    getsa();
    for (int i=0;i<n;i++)
    {
        if (sa[i]<n/2)
        {
            ans[cnt++]=s[sa[i]+n/2-1];
        }
    }
    for (int i=0;i<cnt;i++) printf("%c",ans[i]);
} 

猜你喜欢

转载自blog.csdn.net/liangzihao1/article/details/82219400
今日推荐