HDU 4300 Clairewd’s message(扩展KMP)
这题的意思就是首先有一个字母的转换表,就是输入的第一行的字符串,就是'a'转成第一个字母,'b'转成转换表的第二个字母·······
然后下面一个字符串是密文+明文的形式的字符串。
就是说前后两段是重复的,只不过通过转换表转换了下。
而且后面一段可能不完整。
这道题问的就是将1个串如何变为stringA+stringB的形式,使得stringA是stringB经过映射得到相同的串。映射那步其实没有什么价值,假设str为原串s经过映射后得到的串,我们可以以str为模式串,以s为原串做一次扩展KMP,得到extend数组,extend[i]表示原串以第i开始与模式串的前缀的最长匹配。经过O(n)的枚举,我们可以得到,若extend[i]+i=len且i>=extend[i]时,表示stringB即为该点之前的串,stringA即为该点之前的str串,最后输出即可。
#include<bits/stdc++.h> using namespace std; const int M=2e5+5; char sa[M],sb[M],mima[M]; int lena,lenb; int p[M],ex[M]; map<char,char>mp; //p数组是用来让B串自己匹配自己的 void exkmp() { p[1]=lenb; int x=1; while(sb[x]==sb[x+1]&&x+1<=lenb) x++;//因为我们p[1]是具有一定性,所以我们不能直接用,所以要先暴力求出p[2] p[2]=x-1; int k=2; for(int i=3;i<=lenb;i++) { int pp=k+p[k]-1,L=p[i-k+1];//pp实际上是p if(i+L<pp+1) p[i]=L;//i-k+L<pp-k+1化简后i+L<pp else { int j=pp-i+1; if(j<0) j=0; while(sb[j+1]==sb[i+j]&&i+j<=lenb) j++; p[i]=j; k=i; } } x=1; while(sa[x]==sb[x]&&x<=lenb) x++;//ex[1]并不具有一定性,所以我们暴力求出ex[1] ex[1]=x-1; k=1; for(int i=2;i<=lena;i++) { int pp=k+ex[k]-1,L=p[i-k+1]; if(i+L<pp+1) ex[i]=L; else { int j=pp-i+1; if(j<0) j=0; while(sb[j+1]==sa[i+j]&&i+j<=lena&&j<=lenb) j++; ex[i]=j; k=i; } } } int main(){ int t; scanf("%d",&t); while(t--){ scanf("%s%s",mima+1,sa+1); lena=strlen(sa+1); lenb=lena; for(int i=1;i<=strlen(mima+1);i++) mp[mima[i]]='a'+i-1; for(int i=1;i<=lena;i++) sb[i]=mp[sa[i]]; sb[lena+1]=0; exkmp(); int i; for(i=1;i<=lena;i++) if(i-1+ex[i]>=lena&&i-1>=ex[i]) break; for(int j=1;j<i;j++) printf("%c",sa[j]); for(int j=1;j<i;j++) printf("%c",mp[sa[j]]); puts(""); } return 0; }