题解:UVA12467 Secret Word
Idea
使用 KMP 算法。
约定: 表示把 翻转过来得到的串。
首先考虑如果要求 是 的前缀,那么答案就会是 。
证明:由 数组(即 border)的定义, 表示 中的最长前缀与后缀相等的长度,很显然就是 的 。
那么现在要求 为 的前缀,也就意味着 为 的后缀。
所以我们把 翻转后拼在后面。
接下来我们手搓一个字符串:。
答案是 。
把 翻转后拼在后面,得:。
我们对这个字符串 KMP,就可以得到 数组,就是 的 border。
要满足题目要求,需要这个答案 同时是 的前后缀,就是 border。
其次,我们的答案反转后作为后缀一定是出现在后面拼接的串中。
所以答案就是 ,其中 。
但是对于这组样例:,把 翻转后拼在后面,得到 。
不难发现 。但是事实上答案并不是 。
因为我们的 border 横跨了 和 两个字符串,所以答案是错误的。
所以我们可以在 和 两个字符串之间加上一个特别的字符,就可以避免这种情况,不过要注意下标的改变。
AC Code:
#include<bits/stdc++.h>
using namespace std;
char s[2000005];
int n,nxt[2000005],T;
int main() {
cin>>T;
while(T--) {
cin>>s;
n=strlen(s);
memset(nxt,0,sizeof(nxt));
for(int i=n; i>=1; i--) {
s[i]=s[i-1];
}
s[n+1]='+';
for(int i=1; i<=n; i++) {
s[n*2+2-i]=s[i];
}
for(int i=2,j=0; i<=n*2+1; i++) {
while(j>0&&s[j+1]!=s[i])j=nxt[j];
if(s[j+1]==s[i])j++;
nxt[i]=j;
}
int t=n+1;
for(int i=n+1; i<=n*2+1; i++) {
if(nxt[i]>nxt[t]) {
t=i;
}
}
for(int i=nxt[t]; i>=1; i--)cout<<s[i];
cout<<endl;
}
return 0;
}

浙公网安备 33010602011771号