Loading

luoguP8085 [COCI2011-2012#4] KRIPTOGRAM 题解(KMP)

/*
给定明文和密文,密文与明文的某个字串格式相同,找出密文出现的最早位置。
如:明文 aaabcdabc
	密文 xy
	ans:3 

解:容易想到 KMP算法。
可以发现,密文和对应子串的格式相同。
此时可以想到:以相对位置的形式来维护格式。
设 ai表示明文中与第 i 个字符相同的最近字符(左)的距离,bi同理。
在输入时预处理,对处理出来的数组进行 KMP匹配。
但普通的 KMP匹配无法进行,下面举出反例:
如: 明文 caababc
	 密文 xxyxyz 
	数组A:inf inf 1 inf 2 2 6 
	数组B:inf 1 inf 2 2 inf
正确答案应为 2,但普通 KMP会匹配失败。
此时需加入特判,见代码。 
*/
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int inf=1e9+7;
int T=1,cnta,cntb,a[1000010],b[1000010],pre[1000010];
string s;
map<string,int> lst;
void prefix(){
	int j=0;
	for(int i=2;i<=cntb;i++){
		while(j&&b[i]!=b[j+1]) j=pre[j];
		if(b[i]==b[j+1]) j++;
		pre[i]=j;
	}
}
void kmp(){
	int j=0;
	for(int i=1;i<=cnta;i++){
		while(j&&(b[j+1]==inf&&a[i]<=j||b[j+1]!=inf&&a[i]!=b[j+1])) j=pre[j];
		//分类讨论。
		//1.当密文位为 inf 时:明文位与最近相同字符的距离若还在匹配范围内,则失配。 
		//2.当密文位不为 inf 时:明文位与密文位若不相同,则失配。 
		if(!(b[j+1]==inf&&a[i]<=j)||(b[j+1]!=inf&&a[i]!=b[j+1])) j++;
		if(j==cntb){
			cout<<i-cntb+1;
			return ;
		}
	}
}
void solve(){
	while(cin>>s){
		if(s=="$") break;
		if(!lst[s]) a[++cnta]=inf;
		else a[++cnta]=cnta-lst[s];
		lst[s]=cnta;
	}
	lst.clear();
	while(cin>>s){
		if(s=="$") break;
		if(!lst[s]) b[++cntb]=inf;
		else b[++cntb]=cntb-lst[s];
		lst[s]=cntb;
	}
	prefix();
	kmp();
}
int main(){
//	freopen(".in","r",stdin);
//	freopen(".out","w",stdout);
	while(T--){
		solve();
	}
	return 0;
}

  

posted @ 2022-08-31 10:44  Ryder00  阅读(81)  评论(0)    收藏  举报