题解
给定两个字符串,第一个字符串为字符串的转换规则,(如第二个例子,当第二个字符串中出现q字符后,就要把它变为a字符,即q对应a,w对应b)。
第二个字符串,前一部分为密文,就是需要你按照转换规则,转换的字符串,后一部分为原文。但是原文的长度不知道,也可能原文给的不全,但是密文是完整的。需要你补全第二个字符串。求出最短的字符串。
易知如果存在密文和明文对应,密文长度一定大于等于明文长度,并且密文长度越长,对应密文+明文(即最后结果)越长。故贪心的想,我们希望找一个尽量短的密文。
做法如下。首先预处理,将密文和明文的混合文分别转换为全密文和全明文。再将从混合文和全密文Hash。从中间开始枚举位置,判断混合文的前缀和全密文的后缀hash值是否相等,若相等则当前位置为混合文的密文与明文的分界线。
代码
#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ull;
const int nmax = 1e5 + 100;
const int INF = 0x3f3f3f3f;
const ull p = 67;
int t,len;
char mmp[26]; char code[26];
char str[nmax], trans[nmax], ori[nmax];
ull hashstr[nmax], hashtrans[nmax], pp[nmax] = {0,p};
inline ull strsub(int l, int r){
return hashstr[r] - hashstr[l-1] * pp[r - l + 1];
}
inline ull transsub(int l, int r){
return hashtrans[r] - hashtrans[l-1] * pp[r - l + 1];
}
int main() {
for(int i = 2;i<nmax;++i) pp[i] = pp[i-1] * p;
scanf("%d",&t);
while(t--){
memset(str,0,sizeof str); memset(trans,0,sizeof trans);memset(ori,0,sizeof ori);
scanf("%s",mmp); scanf("%s",str+1);
for(int i = 0;i<26;++i){int pos = mmp[i] - 'a'; code[pos] = i;}
len = strlen(str+1);
for(int i = 1;i<=len;++i) trans[i] = mmp[str[i] - 'a'];
for(int i = 1;i<=len;++i) ori[i] = code[str[i] - 'a'] + 'a';
hashstr[1] = str[1], hashtrans[1] = trans[1];
for(int i = 2;i<=len;++i)
hashstr[i] = hashstr[i-1] * p + str[i],
hashtrans[i] = hashtrans[i-1] * p + trans[i];
int pos = (len+1) / 2;
bool isfind = false;
for(int i = pos+1;i<=len;++i){
int lens = len - i + 1;
ull tarfront = strsub(1,lens);
ull tarback = transsub(i,len);
if(tarfront == tarback){
for(int j = 1;j<i;++j) printf("%c",str[j]);
for(int j = 1;j<i;++j) printf("%c",ori[j]);
isfind = true; printf("\n");
break;
}
}
if(isfind){ // do nothing
}else printf("%s%s\n",str+1,ori+1);
}
return 0;
}