将s2当做密文进行解密为sts2(明+?),完成后将s2(密+明)和sts2进行匹配 。
因为密文解密后即为明文,但是 所给的s2明文不全,所以只可能部分匹配,或不匹配,所以,只需找到匹配的点以及匹配的长度是否大于等于s2.length(),若是,则0-i为密文,明文则在对应的sts2里找。
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
const int N = 100000+5;
const int inf = 0x3f3f3f3f;
int Next[N];//表示为以模式串中以i为起点的后缀字符串和模式串的最长公共前缀长度.
int Extend[N];//表示为以字符串中以i为起点的后缀字符串和模式串的最长公共前缀长度.
string s, t;
void init() {
memset(Next, 0, sizeof(Next));
memset(Extend, 0, sizeof(Extend));
}
void GetNext(string s, int len) {
Next[0] = len;
int cnt = 0, pos = 0;
while(cnt<len-1 && s[cnt] == s[cnt+1]) {
cnt++;
}
Next[1] = cnt;
pos = 1;
for(int i=2; i<len; i++) {
int P = pos+Next[pos], L = Next[i-pos];
if(P <= L+i || P<=i) {
if(P <= i) {
P = i;
}
while(P < len && s[P] == s[P-i]) {
P++;
}
Next[i] = P-i;
pos = i;
} else Next[i] = L;
}
}
bool GetExtend(string s1, int len1, string s2, int len2) {
// cout << s1 << " " << s1.length() <<endl << s2 << " " << s2.length() << endl;
GetNext(s2, len2);
int cnt = 0, pos;
while(s1[cnt] && s2[cnt] && s1[cnt]==s2[cnt]) {
cnt++;
}
Extend[0] = cnt;
pos = 0;
bool flag = false;
if(cnt == len2) flag=true;
for(int i=1; i<len1; i++) {
int P = pos+Extend[pos], L = Next[i-pos];
// cout << pos << "+" << Next[pos] << " :" << L << "+" << i << endl;
if(P <= L+i || P<=i) {
if(P <= i) {
P = i;
}
while(P < len1 && s1[P] == s2[P-i]) {
P++;
}
Extend[i] = P-i;
pos = i;
} else Extend[i] = L;
if(Extend[i] == len2) flag = true;
}
return flag;
}
int main() {
int T;
string s1, s2;
cin >> T;
while(T--) {
init();
cin >> s1 >> s2;
int i;
string sts1(s1.length(), 'a'), sts2(s2.length(), 'a');//必须初始化
for(i=0; s1[i]; i++) {
sts1[s1[i]-'a'] = i+'a';
}
for(i=0; s2[i]; i++) {
sts2[i] = sts1[s2[i]-'a'];
}
bool flag = GetExtend(s2, s2.length(), sts2, sts2.length());
for(i=0; i<s2.length(); i++) {
// cout << i << ": " << Extend[i] << "=" << s2.length() << endl;
if(i+Extend[i]>=s2.length() && i>= Extend[i]) {
break;
}
}
cout << s2.substr(0, i) << sts2.substr(0, i) << endl;
}
return 0;
}