2018上海大都会赛 E题 Thinking-Bear's necklace

 

题意:

一个字符串的环,可以任意断开,使的子串的最大回文串最长,输出长度。

但是你有两次将一个字符修改成任意字符的机会。

题解:

字符串Hash

将串延长1倍,枚举回文串的中间点,看看在最多修改2次的前提下最多有多长。

具体方法:

首先二分出可以向两侧扩展的最大长度,然后跳过一个字符(意味一次修改),再二分最大长度,再跳过,再二分即可。

代码: 

#include<bits/stdc++.h>
#define N 200010
#define INF 1e9
#define LL long long
#define pb push_back
#define cl clear
#define si size
#define lb lowwer_bound
#define eps 1e-8
#define P 1000000007
#define M 377
#define IO ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
using namespace std;
  
LL h1[N],h2[N],p[N];int a1,len;
char x[N];
  
LL spy(LL *h,int l,int r)
{
    return (h[r]-h[l-1]*p[r-l+1]%P+P)%P;
}
  
int cal(int x,int y)
{
    int l=1,r=min((len/2+x-y-1)/2,min(len-y,x-1)); int ans;
    if (spy(h1,x-1,x-1)!=spy(h2,len-y,len-y)) return 0;
    while(r-l>=0)
    {
        int t=(l+r)>>1;
        if (spy(h1,x-t,x-1)==spy(h2,len-y+1-t,len-y))
        {
            ans=t;
            l=t+1;
        }else r=t-1;
    }
    return ans;
}
int main()
{
    IO
    p[0]=1;for (int i=1;i<N;i++) p[i]=p[i-1]*M%P;
    int T;
    cin>>T;
    while(T--)
    {
        cin>>x+1; len=strlen(x+1); len<<=1;
        for (int i=len/2+1;i<=len;i++) x[i]=x[i-len/2];
        for (int i=1;i<=len;i++) h1[i]=(h1[i-1]*M+x[i])%P;
        for (int i=1;i<=len;i++) h2[i]=(h2[i-1]*M+x[len-i+1])%P;
        int ans=0;
        for (int i=1;i<=len;i++)
        {
            int max_len=min(len-i,i-1);int tmp=0;
            max_len=min(max_len,(len/2-1)/2);
            if (max_len<=0) continue;
            a1=cal(i,i);
            if (max_len==a1)
            {
                ans=max(ans,a1);
                continue;
            }else tmp=a1+1;
            ans=max(ans,tmp);
            max_len-=tmp;
            if (max_len<=0) continue;
            a1=cal(i-tmp,i+tmp);
            if (max_len==a1)
            {
                ans=max(ans,a1+tmp);
                continue;
            }else tmp+=a1+1;
            ans=max(ans,tmp);
            max_len-=tmp;
            if (max_len<=0) continue;
            a1=cal(i-tmp,i+tmp);
            tmp+=a1;
            ans=max(ans,tmp);
        }
        cout<<2*ans+1<<endl;
    }
}

猜你喜欢

转载自blog.csdn.net/nudt_spy/article/details/81503333