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

转载于:https://www.cnblogs.com/AzraelDeath/p/7561758.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值