Jzoj2937 监听还原

Alice和Bob正在悄悄地给对方发信息,信息都是由英文小写字母组成的,他们约定,所有的字母都得经过一个字母表进行变换,以防泄漏。另一方面John却在监听。

John发现,Alice和Bob通信的时候,总是先发送加密后的密文,然后紧接着发送原文。

但是Alice和Bob似乎也意识到了似乎有人监听,有时候会随意中断了他们的通信。不过每次都是在发送完密文之后才停止传送的。也就是说,John截获到的信息是密文的全文以及前一部分原文。原文可能一个字符都没有,也可能原文的全文都被截获。

现在John比较头疼,他虽然已经得到了他们两个人通信的加密字母表,但是分不清楚什么地方是密文和明文的分界线。你能帮他还原回完整的传输内容吗?

如果有多种可能时,John认为那个最短的信息才是原始的。
解法,我们将原串和转置后的串分别求hash函数,让后就是枚举分割点O(1)判断相等了,复杂度O(N)
#pragma GCC opitmize("O3")
#pragma G++ opitmize("O3")
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define L long long
using namespace std;
char s[200010]={0},c[26],r[26];
L b[100010],h1[100010],h2[100010],n;
__attribute__((optimize("-O3"))) inline L gH1(int l,int r){ return h1[r]-h1[l-1]*b[r-l+1]; }
__attribute__((optimize("-O3"))) inline L gH2(int l,int r){ return h2[r]-h2[l-1]*b[r-l+1]; }
int main(){
	scanf("%s%s",c,s+1); 
	*b=1; *h1=*h2=0; n=strlen(s+1);
	for(int i=0;i<26;++i) r[c[i]-'a']=i;
	for(int i=1;i<=n;++i){
		b[i]=b[i-1]*27;
		h1[i]=h1[i-1]*27+s[i]-'a';
		h2[i]=h2[i-1]*27+c[s[i]-'a']-'a';
	}
	for(int i=n+2+(n&1)>>1;i<=n;++i)
		if(gH1(1,n-i+1)==gH2(i,n)){
			int m=i-(n-i+1)-1,l=n-i+1;
			for(int j=1;j<=m;++j) s[j+n]=r[s[j+l]-'a']+'a';
			puts(s+1); puts("");return 0;
		}
	for(int j=1;j<=n;++j) s[j+n]=r[s[j]-'a']+'a';
	puts(s+1);
}


posted @ 2017-09-21 16:16  扩展的灰(Extended_Ash)  阅读(109)  评论(0编辑  收藏  举报