BestCoder Round #49 Three Palindromes 即 hdu5340 (manacher算法)

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

Recommend
hujie   |   We have carefully selected several similar problems for you:   5352  5351  5350  5349  5348 
 
解析:摘自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)O(N^2/32)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;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值