秘密信息

题目描述

Irene想用一下的方法加密一条信息(这是她从密码学书上自学来的):

假定这条信息可以用一个字符串S表示,其中S=BCAAD.(其中'.'代表字符串结尾)。Irene首先把S的所有循环同构串写下来(所谓循环同构即是不断地把字符串开头的字符移动到尾端):

BCAAD.

CAAD.B

AAD.BC

AD.BCA

D.BCAA

.BCAAD

接下来她会把这些字符串都排序:

.BCAAD

AAD.BC

AD.BCA

BCAAD.

CAAD.B

D.BCAA

接下来她会把这些字符串的最后一位按照顺序写下来得到加密串T=DCA.BA 现在Irene发现在密码学的书上写着一条来历不明的加密串T。她迫切地知道,如果信息是按照这种方式加密的,那么原串是什么?

输入输出格式

输入格式:

一行一个由大写字母构成,长度为N的字符串(但字符串有且只有一个'.')。

输出格式:

输出一行,输出原串。数据保证有唯一解。

说明

对于20%的数据,2<=N<=10;
对于50%的数据,2<=N<=27,
字符串内部的字母互不相同。
对于100%的数据,2<=N<=30000。


这里稍稍从应试一点的角度来谈谈这个题目吧。

首先这是一道NOIp的模拟题,NOIp的模拟题考纯字符串,会考高级算法吗?

KMP,字典树估计就顶破天了,这两个应该比较好看出来。

那么对待这个题的思维方式就是:多玩样例,多自己写样例玩,多观察猜想

.BCAAD

AAD.BC

AD.BCA

BCAAD.

CAAD.B

D.BCAA

比如如上这个是排序后的字符串,最后一列的所有字符即是原串中的一个元素,将这些字符排序,得到的不就是第一列的东西了吗?由此我们得到了元素的位置关系

这个性质,多写写玩玩样例应该就可以发现,但是,因为有重复元素,所以我们并不知道某些元素的具体的位置关系,不过已经有50分了

怎么办?继续玩。

发现每个数在最左列出现的第\(i\)次,对应在最右列第\(i\)次出现的它。

于是,可以搞了


code:

#include <cstdio>
#include <algorithm>
const int N=30010;
int a[N],n,sor[N],g[28][N],to[N],cnt[28];
void dfs(int now)
{
    if(now==1) return;
    printf("%c",sor[now]+'A'-1);
    dfs(to[now]);
}
int main()
{
    int c=getchar();
    while((c>='A'&&c<='Z')||c=='.')
    {
        if(c=='.') a[++n]=0;
        else a[++n]=c+1-'A';
        c=getchar();
    }
    for(int i=1;i<=n;i++)
        sor[i]=a[i];
    std::sort(sor+1,sor+1+n);
    for(int i=1;i<=n;i++)
        g[sor[i]][++g[sor[i]][0]]=i;//某个数字的第几个的编号
    for(int i=1;i<=n;i++)
        to[g[a[i]][++cnt[a[i]]]]=i;
    dfs(to[1]);
    printf(".\n");
    return 0;
}