HDU 5340 Three Palindromes ——BestCoder Round #49

Three Palindromes

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)


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
 

Source
BestCoder Round #49 ($)
/************************************************************************/

附上该题对应的中文题

Three Palindromes

 
 
 Time Limit: 2000/1000 MS (Java/Others)
 
 Memory Limit: 65536/65536 K (Java/Others)
问题描述
判断是否能将字符串S分成三段非空回文串。
输入描述
第一行一个整数T,表示数据组数。T \leq 20T20
对于每一个组,仅包含一个由小写字母组成的串。1 \leq |S| \leq 200001S20000
输出描述
对于每一组,单行输出"Yes" 或 "No"。
输入样例
2
abc
abaadada
输出样例
Yes
No
/****************************************************/

出题人的解题思路:

对原串前缀和后缀作一个01标记pre[i],suf[i]表示1-i和i-n能否能形成回文。记以i为中心的回文半径为r(i)。

这些都可以在O(N)时间内求出。也可以使用Hash+二分等方法O(NlogN)内求出。

我们考虑中间一个回文串的位置,不妨设它是奇数长度(偶数类似)。

那么问题变成了求一个i和d使得1<=d<=r(i)且pre[i-d]和suf[i+d]为真。

枚举i,实际上就是问pre[i-r(i)..i-1]和suf[i+1..i+r(i)]取反后 这两段有没有一个位置两者均为1,也就是and后不为0,暴力压位即可。

总时间复杂度为O(N^2/32)O(N2/32)

说实话,出题人给的题解思路真心有点令人费解,或许是因为我还是一名菜鸟的缘故吧。前段时间刚好了解到了Manacher算法(一种计算最长回文子串的时间复杂度为O(n)的算法,想要学习一下的点链接吧Manacher算法),于是就拉了一下模板。

首先呢,Manacher算法中有一个p数组,可以记录回文子串在原串中的长度,然后枚举三个非空回文子串中的第一个和第三个(因为这两个比较特殊,毕竟接地气嘛得意,因为第一个是原字符串的开始,第三个是原字符串的结束),接着判断中间的回文串是否能接触到两边的回文串即可

/*
*/
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<queue>
#include<math.h>
#include<vector>
#include<map>
#include<set>
#include<string>
#include<algorithm>
#include<iostream>
#define exp 1e-10
using namespace std;
const int N=20005;
char s[N*2];
int p[N*2],top[N*2],tail[N*2];
void Manacher() {

    int len = strlen(s), id = 0, maxlen = 0;
    for (int i = len;i >= 0;--i) {
        s[i + i + 2] = s[i];
        s[i + i + 1] = '#';
   }
 s[0] = '*';
 for (int i = 2;i < 2 * len + 1;++i) {
        if (p[id] + id > i)p[i] = min(p[2 * id - i], p[id] + id - i);
        else p[i] = 1;
        while (s[i - p[i]] == s[i + p[i]])++p[i];
        if (id + p[id] < i + p[i])id = i;
        if (maxlen < p[i])maxlen = p[i];
    }
    //cout << maxlen - 1 << endl;
}
int main()
{
    int t,i,j,k,k1,k2,r1,r2,mid;
    bool flag;
    scanf("%d",&t);
    while(t--)
    {
        k1=k2=0;flag=false;
        scanf("%s",s);
        Manacher();
        k=strlen(s);
        for(i=2;i<k-1;i++)
        {
            if(i-p[i]==0)
                top[k1++]=i;
            if(i+p[i]==k)
                tail[k2++]=i;
        }
        for(i=0;i<k1;i++)
        {
            for(j=k2-1;j>=0;j--)
            {
                r1=top[i]+p[top[i]];
                r2=tail[j]-p[tail[j]];
                if(r1>r2)
                    break;
                mid=(r1+r2)/2;
                if(p[mid]-1>=mid-r1)
                    flag=true;
                if(flag)
                    break;
            }
            if(flag)
                break;
        }
        if(flag)
            printf("Yes\n");
        else
            printf("No\n");
    }
    return 0;
}

菜鸟成长记,欢迎大家和我一起学习



你可能感兴趣的:(算法,ACM,manacher算法,回文串)