当前位置: 代码迷 >> 综合 >> HDU 5340 Three Palindromes ——BestCoder Round #49
  详细解决方案

HDU 5340 Three Palindromes ——BestCoder Round #49

热度:54   发布时间:2023-12-12 11:02:31.0

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(N?2??/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");elseprintf("No\n");}return 0;
}

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



  相关解决方案