题解:UVA12467 Secret Word

Idea

使用 KMP 算法。

约定:reverse(s)\operatorname{reverse}(s) 表示把 ss 翻转过来得到的串。

首先考虑如果要求 ppss 的前缀,那么答案就会是 max(nxti)\max(nxt_i)

证明:由 nxtnxt 数组(即 border)的定义,nxtinxt_i 表示 s1is_{1\to i} 中的最长前缀与后缀相等的长度,很显然就是 s1is_{1\to i}pp

那么现在要求 reverse(p)\operatorname{reverse}(p)ss 的前缀,也就意味着 ppreverse(s)\operatorname{reverse}(s) 的后缀。

所以我们把 ss 翻转后拼在后面。

接下来我们手搓一个字符串:abcdbacd\texttt{abcdbacd}

答案是 ba\texttt{ba}

ss 翻转后拼在后面,得:abcdbacddcabdcba\texttt{abcdbacddcabdcba}

我们对这个字符串 KMP,就可以得到 nxtnxt 数组,就是 s1is_{1\to i} 的 border。

要满足题目要求,需要这个答案 pp 同时是 s1is_{1\to i} 的前后缀,就是 border。

其次,我们的答案反转后作为后缀一定是出现在后面拼接的串中。

所以答案就是 max(nxti)\max(nxt_i),其中 i[n+1,2×n]i\in[n+1,2\times n]

但是对于这组样例:abbacab\texttt{abbacab},把 ss 翻转后拼在后面,得到 abbccabbaccbba\texttt{abbccabbaccbba}

不难发现 nxt8=3nxt_8=3。但是事实上答案并不是 bba\texttt{bba}

因为我们的 border 横跨了 ssreverse(s)\operatorname{reverse}(s) 两个字符串,所以答案是错误的。

所以我们可以在 ssreverse(s)\operatorname{reverse}(s) 两个字符串之间加上一个特别的字符,就可以避免这种情况,不过要注意下标的改变。

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;
}
posted @   Weslie_qwq  阅读(2)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示