HDU 5340 Three Palindromes(Manacher)

Problem Description:
Can we divided a given string S into three nonempty palindromes?
 
Input:
First line contains a single integer T20 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

题意:判断一个字符串是否能完全分成三个回文串。

分析:一个字符串如果想要分成三个字符串,那么肯定第一个回文串的左端点肯定是第一个字符,第三个回文串的右端点肯定是最后一个字符,那么我们只需要判断中间的字符串是否是回文串就行啦。

#include<stdio.h>
#include<string.h>
#include<queue>
#include<math.h>
#include<stdlib.h>
#include<algorithm>
using namespace std;

const int N=1e6+10;
const int INF=0x3f3f3f3f;
const int MOD=1e9+7;

typedef long long LL;

char s[N], str[N];
int r[N], k, left[N], right[N], L, R;

void Palind()
{
    int i, index = 0;

    for (i = 2; str[i] != ''; i++)
    {
        r[i] = 1;

        if (r[index]+index > i) r[i] = min(r[2*index-i], r[index]+index-i);

        while (str[i+r[i]] == str[i-r[i]]) r[i]++;

        if (r[i]+i > r[index]+index) index = i;

        if (r[i] == 1) continue; ///半径是1的肯定是‘#’,不能统计
        if (i-r[i] == 0) left[L++] = 2*r[i]-1; ///left保存每个左端点是第一个字符的回文串的直径
        if (i+r[i] == k) right[R++] = 2*r[i]-1; ///right保存每个右端点是最后一个字符的回文串的直径
    }
}

int main ()
{
    int T, i, j, y, x, flag, len;

    scanf("%d", &T);

    while (T--)
    {
        k = 2;
        scanf("%s", s);

        memset(r, 0, sizeof(r));
        memset(str, 0, sizeof(str));
        L = R = flag = 0;

        str[0] = '$';
        str[1] = '#';

        for (i = 0; s[i] != ''; i++)
        {
            str[k++] = s[i];
            str[k++] = '#';
        }
        str[k] = '';

        Palind();

        for (i = 0; i < L; i++)
        {
            for (j = 0; j < R; j++)
            {
                y = k-right[j]; ///计算右端点是最后一个字符的回文串的左端点
                if (left[i] >= y) continue; ///如果左端点是第一个字符的回文串的右端点与右端点是最后一个字符的回文串的字符重合,则跳过

                len = y-left[i]+1; ///计算中间字符的长度
                x = r[len/2+left[i]]; ///计算以中间字符中心为中心的回文串的半径
                if (x*2-1+left[i]+right[j] >= k) ///计算三个回文串的长度之和是否>=k
                {
                    flag = 1;
                    break;
                }
            }

            if (flag == 1) break;
        }

        if (flag == 1) printf("Yes
");
        else printf("No
");
    }

    return 0;
}
原文地址:https://www.cnblogs.com/syhandll/p/4959417.html