这题描述简直惊人。其实就是说先给你一个密码表。然后给你一个不一定完整的串。原串满足前一半是密码,后一半是明码。要求你最小的补全这个串。首先我们要明确:设给的串长度为len,则1…(len+1)/2的字母一定是密码。我们可以把这一部分作为模式串,去匹配后面的串。(当然因为我们假定后面的串都是明码,所以我们要把后面的串翻译成密码来匹配)。我们假设最后一位匹配到了模式串的第k位。则说明1..len-k都是密码。我们按此输出原串即可。注意别忘了加\0,害我WA了好久。打算一会再写个exkmp的补上。。
#include <cstdio>
#include <cstring>
#define N 100010
int tst,n,fail[N];
char a[255],b[255],s[N<<1],s2[N];
inline void getfail(int m){
int k=0;fail[1]=0;
for(int i=2;i<=m;++i){
while(k&&s[k+1]!=s[i]) k=fail[k];
if(s[k+1]==s[i]) ++k;
fail[i]=k;
}
}
int main(){
// freopen("a.in","r",stdin);
scanf("%d",&tst);
while(tst--){
n=0;
scanf("%s%s",a+'a',s+1);int len=strlen(s+1);
for(int i='a';i<='z';++i) b[a[i]]=i;
for(int i=(len+1)/2+1;i<=len;++i) s2[++n]=a[s[i]];
getfail((len+1)/2);int k=0;
for(int i=1;i<=n;++i){
while(k&&s[k+1]!=s2[i]) k=fail[k];
if(s[k+1]==s2[i]) ++k;
}int m=len;
for(int i=k+1;i<=len-k;++i) s[++m]=b[s[i]];
s[++m]=0;//别忘了加\0
puts(s+1);
}
return 0;
}