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; }