题目描述
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;
}