题目链接 HDU4300
题目大意:先提供一个由a到z的明文到密文的匹配,之后在下一行中有包含密文和一部分明文的字符串,我们需要把明文的部分补全并输出来。
分析:设明文密文匹配的字符串为s,需要补全的字符串为s1。s1中一定包含全部的密文,则将其全部当做密文翻译回明文时前面也一定是全部的明文。我们可以先将s1后半段截取后复制到s2上,s2包含需要补全的明文。然后用翻译后的s1作为模式串对s2进行匹配,返回s2后缀与s1前缀相等的长度,剩下的用s1输出即可。
#include <iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
char s1[100005],s2[100005],s[27];
int nexts[100005];
int l1,l2,n;
void get_next()
{
int i=0,j=-1;
nexts[0]=-1;
while(i<l1)
{
if(j==-1||s1[i]==s1[j])
nexts[++i]=++j;
else j=nexts[j];
}
}
int kmp()
{
int i=0,j=0;
get_next();
l2=strlen(s2);//l2代表s2的长度
while(i<l2&&j<l1)
{
if(j==-1||s2[i]==s1[j])
{
i++;j++;
if(i==l2)
return j;
}
else j=nexts[j];
}
return 0;
}
int main()
{
cin>>n;
while(n--)
{
scanf("%s%s",s,s1);
l1=strlen(s1);//l1代表s1的长度
strcpy(s2,s1+(l1+1)/2);
printf("%s",s1);
for(int i=0;i<l1;i++)
{
for(int j=0;j<26;j++)
{
if(s1[i]==s[j])
{
s1[i]='a'+j;
break;
}
}
}
int len=kmp();//len是前缀与后缀最大匹配长度
for(int i=len;i<l1-len;i++)//从len开始添加到s1总长减明文串长度
printf("%c",s1[i]);
cout<<endl;
}
}