HDU - 4300 - Clairewd’s message
将
S
看成密文,转化成明文
可以转化为求
S[i...n]
与
T
的最长公共前缀。这样可以用扩展KMP来做。
扩展KMP
扩展KMP解决求
next[i]
的值为
S2[i...n]
与
S2
的最长公共前置。
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+7;
char S[N],T[N];
int nxt[N],ex[N],n;
//① P=nxt[po]+po,即最长能匹配到的地方。
//此时s[0,P-po]=S[po,P]
//那么s[i-po,P-po]=s[i,P]
//注意nxt的定义,可以得到如下结论。
//如果nxt[i-po]+i<P ,即不能延伸P的位置,那么此时nxt是确定的。
//② 如果延伸超过了,那么要重新计算P和po,
//因为s[i-po]=s[i,P],所以只需要从原来的P开始就行了。
//getNext是自己在自己身上求extend
//所以求extend的过程与求Next差不多。
void getNext(char s[])
{
int i=0,j,po;
nxt[0]=n;
while(i+1<n&&s[i]==s[i+1]) ++i;
nxt[1]=i;
po=1;
for(i=2;i<n;++i)
{
if(nxt[i-po]+i<nxt[po]+po)
nxt[i]=nxt[i-po];
else
{
j=max(0,nxt[po]+po-i);
while(i+j<n&&s[j]==s[j+i]) ++j;
nxt[i]=j;
po=i;
}
}
}
//求出s1[i,...,n-1]与s2的最长公共前缀
void exkmp(char s1[],char s2[])
{
int i=0,j,k,po;
while(s1[i]==s2[i]&&i<n) ++i;
ex[0]=i;
po=0;
for(i=1;i<n;++i)
{
if(nxt[i-po]+i<ex[po]+po)
ex[i]=nxt[i-po];
else
{
j=max(0,ex[po]+po-i);
while(i+j<n&&j<n&&s1[j+i]==s2[j]) ++j;
ex[i]=j;
po=i;
}
}
}
char f[30],inv[30];
int main()
{
int kase;
scanf("%d",&kase);
while(kase--)
{
scanf("%s",f);
scanf("%s",S);
for(int i=0;i<26;++i)
inv[f[i]-'a']=i+'a';
n=strlen(S);
for(int i=0;i<n;++i) T[i]=inv[S[i]-'a'];
T[n]=0;
getNext(T);
exkmp(S,T);
int L=(n+1)/2;
for(int i=(n+1)/2;i<n;++i,++L)
if(ex[i]+i==n) break;
for(int j=0;j<L;++j) putchar(S[j]);
for(int j=0;j<L;++j) putchar(inv[S[j]-'a']);
puts("");
}
}