zoukankan      html  css  js  c++  java
  • 【题解】Luogu P4324 [JSOI2016]扭动的回文串

    原题传送门

    这题实际挺水的

    先对两个字符串分别跑马拉车

    就能求出1、2类扭动回文串最大的长度

    考虑第三类的扭动回文串(S(i,j,k)),一定可以表示为(A(i,l)+A(l+1,j)+B(j,k))(A(i,j)+B(j,l)+B(l+1,k)),其中,第一段与第三段对称(第一段正着Hash和第三段反着Hash相同,数据水(某八位质数都不卡),单模数hash就行),第二段是一个回文子串,三段都可以是空串。

    在A、B串上枚举扭动的回文串的中心mid,不难发现,以其在原串上能扩展出的最长回文子串为第二段进行扩展一定最优。对每个mid,以最长回文子串作为第二段,在A、B串上二分第一、三段的长度,其结果一定最优

    代码(极其丑,常数极大)

    #include <bits/stdc++.h>
    #define getchar nc
    #define N 200005
    #define P 19260817
    using namespace std;
    inline char nc(){
        static char buf[100000],*p1=buf,*p2=buf; 
        return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++; 
    }
    inline char gc(){
        char ch;
        while((ch=getchar())<'A'||ch>'Z');
        return ch;
    }
    inline int read()
    {
        register int x=0,f=1;register char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
        return x*f;
    }
    inline void write(register int x)
    {
        if(!x)putchar('0');if(x<0)x=-x,putchar('-');
        static int sta[20];register int tot=0;
        while(x)sta[tot++]=x%10,x/=10;
        while(tot)putchar(sta[--tot]+48);
    }
    inline int Min(register int a,register int b)
    {
        return a<b?a:b;
    }
    inline int Max(register int a,register int b)
    {
        return a>b?a:b;
    }
    int n,ans,p;
    int a[N],b[N],sum[N],num[N],bin[N],f[N],g[N];
    char ch; 
    inline bool check(register int l1,register int r1,register int l2,register int r2){
        int x=0,y=0;
        x=(sum[r1]-1ll*sum[l1-1]*bin[r1-l1+1]%P)%P;
        y=(num[l2]-1ll*num[r2+1]*bin[r2-l2+1]%P)%P;
        x=(x+P)%P,y=(y+P)%P;
        return x==y?true:false;
    }
    inline int calc(register int j,register int k)
    {
        int l=0,r=Min(j,n-k+1),res=0;
        while(l<=r)
        {
            int mid=l+r>>1;
            if(check(j-mid+1,j,k,k+mid-1))
                res=mid,l=mid+1;
            else
                r=mid-1;
        }
        return res;
    }
    int main()
    {
       	n=read(); 
        bin[0]=1;
        for(register int i=1;i<=n;++i)
            bin[i]=1ll*bin[i-1]*27%P;
        a[0]=b[0]=0;
        a[(n<<1)+2]=b[(n<<1)+2]=28;
        a[1]=b[1]=27;
        for(register int i=1;i<=n;++i)
            ch=gc(),a[i<<1]=ch-'A'+1,a[i<<1|1]=27;
        for(register int i=1;i<=n;++i)
            ch=gc(),b[i<<1]=ch-'A'+1,b[i<<1|1]=27;
        p=0;
        for(register int i=2;i<=n<<1;++i)
        {
            if(i<=p+f[p])
                f[i]=Min(f[(p<<1)-i],p+f[p]-i);
            while(a[i-f[i]-1]==a[i+f[i]+1])
                ++f[i];
            if(i+f[i]>p+f[p])
                p=i;
        }
        p=0;
        for(register int i=2;i<=n<<1;++i)
        {
            if(i<=p+g[p])
                g[i]=Min(g[(p<<1)-i],p+g[p]-i);
            while(b[i-g[i]-1]==b[i+g[i]+1])
                ++g[i];
            if(i+g[i]>p+g[p])
                p=i;
        }
        for(register int i=2;i<=n<<1;++i)
            ans=Max(ans,Max(f[i],g[i]));
        for(register int i=1;i<=n;++i)
            sum[i]=(1ll*sum[i-1]*27%P+a[i<<1])%P;
        for(register int i=n;i;--i)
            num[i]=(1ll*num[i+1]*27%P+b[i<<1])%P;
        int l=0,r=0;
        for(register int i=2;i<=n<<1;++i)
        {
            l=(i-f[i]+1)>>1,r=(i+f[i])>>1;
            ans=Max(ans,f[i]+(calc(l-1,r)<<1));
            l=(i-g[i]+1)>>1,r=(i+g[i])>>1;
            ans=Max(ans,g[i]+(calc(l,r+1)<<1));
        }
        write(ans);
        return 0;
     } 
    
  • 相关阅读:
    GIT基本概念和用法总结
    SELECT联动
    PHP无级分类续及搜索功能,分组分页
    PHP管理员登陆、验证与添加(前端验证)
    PHP手写cms 缓存Cache
    将本地文件上传到Ftp上的一些操作【转】
    SQL对时间的处理
    SQL Server游标的使用【转】
    修改数据表字段长度
    Web.Config加密【转】
  • 原文地址:https://www.cnblogs.com/yzhang-rp-inf/p/10256966.html
Copyright © 2011-2022 走看看