题意:
先给定密文到明文的转换表,26个字母,第i个字母c[i]表示密文中的c[i]会转换成明文中的'a'+i。
之后给定一串字符串a,表示密文+明文的组合文本,明文部分由密文部分转换过来,现在不清楚是否完整,让我们求最小长度的可能文本。
题解:
题目的要求就是用最短的字符串补完a,使得a的前半部分翻译后可以得到后面部分。
我们先将a全当做密文转换成b,然后从a的后半部分开始匹配(密文肯定不小明文的长度),得到最大的a的后缀等于b的前缀,说明这部分是明文部分,然后补全即可。
代码:
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <queue>
#include <map>
#include <vector>
using namespace std;
const int maxn=1e5+10;
char a[maxn],b[maxn],c[30],d[30];
int f[maxn];
void getFail(char *P,int *f)//求失配函数
{
int m=strlen(P);
f[0]=f[1]=0;
for(int i=1;i<m;i++)
{
int j=f[i];
while(j&&P[i]!=P[j])j=f[j];
f[i+1]=P[i]==P[j]?j+1:0;
}
}
int find(char *T,char *P,int *f)//KMP算法
{
int n=strlen(T),m=strlen(P);
getFail(P,f);
int j=0;
for(int i=0;i<n;i++)
{
while(j&&P[j]!=T[i])j=f[j];
if(P[j]==T[i])j++;
//if(j==m)printf("%d\n",i-m+1);
}
return j;
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%s%s",c,a);
int i,j,k,n;
for(i=0;i<26;i++)
{
d[c[i]-'a']='a'+i;
}
n=strlen(a);
for(i=0;i<n;i++)b[i]=d[a[i]-'a'];
k=find(a+(n+1)/2,b,f);
//printf("%d\n",k);
for(i=0;i<n-k;i++)printf("%c",a[i]);
for(i=0;i<n-k;i++)printf("%c",b[i]);
printf("\n");
}
return 0;
}