Three Palindromes
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 1132 Accepted Submission(s): 370
Problem Description
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
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
Recommend
解析:摘自FancyCoder
/*
对原串前缀和后缀作一个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(N2/32)。
*/
我的做法并没有用到压位(实际上是我不会),直接裸的manacher算法得出以 i 字符为中心的回文串半径p[i](这里的字符串是已经扩展过的,长度为0~len*2+1),然后直接枚举中心点 i 就好。
代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cctype>
#define maxn 20000
using namespace std;
char ss[maxn+20],s[maxn*2+20];
int p[maxn*2+20],id,mx,len;
bool pre[maxn*2+20],suf[maxn*2+20];
int main()
{
int i,j,k,t,len,c;
while(scanf("%d",&t)!=EOF)
for(i=1;i<=t;i++)
{
scanf("%s",ss),len=strlen(ss);
s[0]='*',s[1]='#';
for(j=0;j<len;j++)
s[2*j+2]=ss[j],s[2*j+3]='#';
k=2*len+1,mx=0,s[k+1]='%';
for(j=1;j<=k;j++)
{
if(mx>j)p[j]=min(p[2*id-j],mx-j);
else p[j]=1;
while(s[j-p[j]]==s[j+p[j]])p[j]++;
if(j+p[j]>mx)mx=j+p[j],id=j;
}
memset(pre,0,sizeof(pre));
memset(suf,0,sizeof(suf));
for(j=2;j<k;j++)
{
if(p[j]==j)pre[j+p[j]-1]=1;
if(j+p[j]==k+1)suf[j-p[j]+1]=1;
}
for(j=4;j<=k-3;j++)
{
for(c=islower(s[j])?1:2;c<=p[j];c+=2)
if(pre[j-c] && suf[j+c])break;
if(c<=p[j])break;
}
if(j>k-3)printf("No\n");
else printf("Yes\n");
}
return 0;
}