HDU5340 Three Palindromes <Manacher>

Three Palindromes

Can we divided a given string S into three nonempty palindromes?

Input
First line contains a single integer T≤20 which denotes the number of test cases.
For each test case , there is an single line contains a string S which only consist of lowercase English letters.1≤|s|≤20000
Output
For each case, output the "Yes" or "No" in a single line.

Sample Input
2
abc
abaadada
Sample Output
Yes
No

标签:Manacher

题目大意:给出字符串S,判断S是否能被分为三段回文串。

看到回文串,可知本题大概和manacher有关。
在manacher中,我们有一个数组f[],f[i]记录从第i位向两边拓展,最长回文串的半径是多少。注意到本题有一个特殊的数据——三,而三段中,只要能确定任意两段,另一端就能确定。而这三段中肯定有两段是覆盖到串首或串尾的。因而我们可以用f[i]是否等于i来确定i位置是否能成为第一个段的中心点,如法炮制可求出第三段。这时我们暴力枚举第一段和第三段,这样确定第二段后,找到此段中心,可通过f[]确定第二段是否是回文串。

最后附上AC代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#define MAX_L 20000
using namespace std;
char s[MAX_L*2+5];
int f[MAX_L*2+5];
bool manacher (char* s0) {
	int len = strlen(s0), pos = 0, r = 0;
	for (int i = 0; i < len; i++)	s[i*2+1] = '#', s[i*2+2] = s0[i];	s[len = len*2+1] = '#';
	for (int i = 1; i <= len; i++) {
		f[i] = (i < r) ? min(f[2*pos-i], r-i) : 1;
		while (i-f[i] >= 1 && i+f[i] <= len && s[i-f[i]] == s[i+f[i]])	f[i]++;
		if (i+f[i] > r)	pos = i, r = i+f[i];
	}
	int lm[MAX_L*2+5], rm[MAX_L*2+5], cntl = 0, cntr = 0;
	for (int i = 1; i <= len; i++) {
		if (f[i] == i && f[i] > 1)	lm[cntl++] = i;
		if (f[len-i+1] == i && f[len-i+1] > 1)	rm[cntr++] = len-i+1;
	}
	for (int i = 0; i < cntl; i++)
		for (int j = 0; j < cntr; j++) {
			int s = lm[i]+f[lm[i]], t = rm[j]-f[rm[j]];
			if (s > t)	continue;
			if (f[s+t>>1] == 1)	continue;
			if (f[s+t>>1]*2-1 < t-s+1)	continue;
			return true;
		}
	return false;
}
int main() {
	int T;
	scanf("%d", &T);
	while (T--) {
		char s0[MAX_L+5];
		scanf("%s", s0);
		if (manacher(s0))	printf("Yes\n");
		else	printf("No\n");
	}
	return 0;
}
posted @ 2017-09-20 15:27  Azrael_Death  阅读(117)  评论(0编辑  收藏  举报