UVALive 4975 - Casting Spells Manacher+科学枚举

29 篇文章 0 订阅
6 篇文章 0 订阅

           题意:

                   给了一个字符串...现在要找这样一个字串:设W为一个字符串..Wr为其逆串..现在要找的是WWrWWr...如果存在..输出其最长的长度..否则输出0..

           题解:

                   先用manacher找出每个位置为中点最长的回文串的长度...然后就是枚举了..简单的说WWrWWr一定也是回文的..而WWr又是回文的..那么就是要找长度4倍数的回文串..并且其前后1/4分点又存在长度为回文串长度为原串的1/2...

                   枚举的时候很多讲究.要不就超时...


Program:

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<set>
#include <stack>
#include<queue>
#include<algorithm>
#include<cmath>
#define oo 1000000007
#define ll long long
#define pi acos(-1.0)
#define MAXN 800005 
using namespace std;   
char str[MAXN],s[MAXN];
int dp[MAXN];
int manacher()
{    
     int l,i,j,w,p,k,ans=0;    
     l=strlen(str);   
	 memset(dp,0,sizeof(dp));  
     s[0]='*';  
	 for (i=0;i<l;i++) s[i*2+1]=str[i],s[i*2+2]='*';  
	 l*=2;   
	 memset(dp,0,sizeof(dp));  
	 dp[0]=ans=1;  w=p=0;    
     for (i=1;i<=l;i++)  
	 {   
            if (i<=w) dp[i]=dp[2*p-i];  
            if (i+dp[i]/2>=w)  
	        {  
                  p=i;  
                  if (w>=i) dp[i]=(w-i)*2;  
                       else w=i;  
                  dp[i]++;  
                  while (w+1<=l && s[w+1]==s[2*p-w-1]) dp[i]+=2,w++;    
            }   
            ans=max(ans,dp[i]/2);
      } 
      return l;  
}
int main()
{       
      int cases,len,i,l,ans,t;  
      scanf("%d",&cases);
      while (cases--)
      {  
             scanf("%s",str);
             len=manacher();
             ans=0;
             for (i=0;i<=len;i+=2)
               if (dp[i]>8)
               {
                      if (dp[i]%8) l=dp[i]-dp[i]%8+1;
                             else  l=dp[i]-7; 
                      for (;l>=ans<<1;l-=8)  
                      {  
                             t=i-l/4;
                             if (dp[t]<l/2) continue;
                             t=i+l/4;
                             if (dp[t]<l/2) continue;  
                             ans=l/2; 
                      }
               }
             printf("%d\n",ans); 
      } 
      return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值