【NOIP2012模拟8.9】监听还原

来源:互联网 发布:淘宝上买东西分期还 编辑:程序博客网 时间:2024/06/15 21:40

题目

Description
Alice和Bob正在悄悄地给对方发信息,信息都是由英文小写字母组成的,他们约定,所有的字母都得经过一个字母表进行变换,以防泄漏。另一方面John却在监听。
John发现,Alice和Bob通信的时候,总是先发送加密后的密文,然后紧接着发送原文。
但是Alice和Bob似乎也意识到了似乎有人监听,有时候会随意中断了他们的通信。不过每次都是在发送完密文之后才停止传送的。也就是说,John截获到的信息是密文的全文以及前一部分原文。原文可能一个字符都没有,也可能原文的全文都被截获。
现在John比较头疼,他虽然已经得到了他们两个人通信的加密字母表,但是分不清楚什么地方是密文和明文的分界线。你能帮他还原回完整的传输内容吗?
如果有多种可能时,John认为那个最短的信息才是原始的。
Input
第一行是密码表格,包含26个小写字母,依次表示a-z加密后的字母。
第二行是John截获到的通信信息。
Output
包含一行,表示还原后的通信信息。
Sample Input
abcdefghijklmnopqrstuvwxyz
abcdab
Sample Output
abcdabcd
Hint
通信长度L<=100000。

小结

这是很多人暴力都过啦,什么鬼?
我用KMP:
首先我们用KMP的自己弄自己,算出p[i];
但是我们在算p的时候要用加密的与前面的比较;
S:abcdaacbda
P:0000112345
然后,我们就找到最后一个,这就是原文被截取的个数。
然后把指针跳到p[len]-1,每次就输出加密字符对应的原文,就好啦。
注意全部一样的情况!

#include<cstdio>#include<iostream>#include<cstring>using namespace std;char tab[100001],s[100001],tabans[100001];long long p[100001];int main(){    scanf("%s",tab+1);    scanf("%s",s+1);    long long  len=strlen(s+1);    int j=0,i=0;    for (i=1;i<=26;++i) tabans[tab[i]-96]=i;    i=-1;    if (tab[s[1]-96]==s[1])    {        for (i=1;i<=len;++i) if (s[i]!=s[i+1]) break;        if (i==len)            if (len%2==0) printf("%s",s+1);                else printf("%s%c",s+1,s[1]);    }    if (i!=len)    {        p[1]=0;        for (i=2;i<=len;++i)        {               while (j>0&&s[j+1]!=tab[s[i]-96]) j=p[j];            if (s[j+1]==tab[s[i]-96]) j++;            p[i]=j;             }        printf("%s",s+1);        char t;        for (i=p[len]+1;i<len-p[len]+1;++i)         {               t=tabans[s[i]-96]+96;            printf("%c",t);        }    }}
原创粉丝点击