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;
}