zoukankan      html  css  js  c++  java
  • 回文串

    1694:回文串

    时间限制: 1000 ms         内存限制: 262144 KB
    【题目描述】

    令F(A,B)表示选择一个串的非空前缀A和串B的非空后缀 使得将串S和串T拼接起来之后是回文串的方案数。

    现在给定两个串A和B,令Ai表示串A的第i长的后缀,Bi为串B的第i长的前缀。

    有Q组询问,第i 组询问给定xi 和yi ,对每组询问求F(Axi,Byi)的值。
    【输入】

    第一行一个字符串str,表示数据类型。

    接下来的两行分别表示字符串A和B。

    接下来一行一个正整数Q,表示询问的个数。

    接下来Q行,每行两个正整数xi 和 yi。
    【输出】

    输出Q行,每行一个整数,表示这一组询问的答案。
    【输入样例】

    B
    newionyzz
    wyxioiwen
    1
    1 1

    【输出样例】

    16

    【提示】

    【样例解释】

    对于样例 1,共有以下 16种方案:

    {S=n,T=n};{S=n,T=en};{S=ne,T=n};{S=ne,T=en};

    {S=ne,T=wen};{S=new,T=en};{S=new,T=wen};{S=new,T=iwen};

    {S=new,T=ioiwen};{S=newi,T=wen};{S=newi,T=iwen};{S=newi,T=oiwen};

    {S=newio,T=iwen};{S=newio,T=oiwen};{S=newio,T=ioiwen};{S=newion,T=oiwen}

    【数据规模】

    对于100%的数据,字符串中只出现小写字母。
    子任务编号    子任务分值    max(|A|,|B|)<=8e5, Q<=1e5.

    【题解】

    首先将B串翻转,方便之后匹配。

    对于前缀后缀拼接而成的回文串,出去A串和B串的最长公共前缀后,剩下的必须是一个回文串。

    例如

    A aba

    B abacdqdc

    拼接为abacdqdcaba。

    此时除去最长公共前缀后是cdqdc

    所以我们可以求出A,B中以每一位开头后头有几个回文串,设为f[i],g[i]。

    统计答案时枚举A,B公共前缀,则答案为∑f[x+i]+g[y+i]+1。i为两串的公共前缀长度。

    求出f,g数组前缀和即可用哈希二分最长公共前缀求解。

    所以现在问题剩下求出f,g

    可以跑一遍马拉车,对于以i为中心的回文串长度为cj[i]。则对f[i-cj[i]+1]到f[i]都有1的贡献可以差分求解,注意关于‘#’的处理。

    时间复杂度

    设ma=max(lena,lenb);

    O(lena+lenb+Q*log2ma).

    代码如下:

    #include<bits/stdc++.h>
    #define int long long
    #define ull unsigned long long
    using namespace std;
    const int N=8e5+5;
    const int cc=131;
    const int mo=998244353;
    int cj[N<<1],n,m,f[N],g[N],q,zc,hu[N<<1],haa2[N],hab2[N],ch2[N];
    char modeyong[10],s[N],t[N],c[N<<1];
    ull haa[N],hab[N],ch[N];
    inline void malache(int pu,int len)
    {
        c[0]='$';c[1]='#';
        for(int i=1;i<=len;i++)
        {
            if(pu==0) c[i*2]=s[i];
            else c[i*2]=t[i];
            c[i*2+1]='#'; 
        }
        int r=0,zai=0;
        len=len*2+1;c[len+1]=')';
        memset(cj,0,sizeof(cj));
        for(int i=1;i<=len;i++)
        {
            if(i<r) cj[i]=min(r-i,cj[zai*2-i]);
            else cj[i]=1;
            while(c[cj[i]+i]==c[i-cj[i]]) cj[i]++;
            if(cj[i]+i>r) r=i+cj[i],zai=i;
        }
        memset(hu,0,sizeof(hu));
        for(int i=1;i<=len;i++)
        {
            int huu=i-cj[i]+1;
            if(huu%2==1) huu++;
            hu[huu]++;
            huu=i+1;
            if(huu%2==1) huu++;
            hu[huu]--; 
        }
    }
    inline int read()
    {
        char c=getchar();
        int x=0,f=1;
        while(!isdigit(c)) {if(c=='-') f=-1;c=getchar();}
        while(isdigit(c)) {x=(x<<3)+(x<<1)+c-'0';c=getchar();}
        return x*f;
    }
    inline void get_hash()
    {
        ch[0]=1;ch2[0]=1;
        for(int i=1;i<=N-3;i++)
            ch[i]=ch[i-1]*cc,ch2[i]=(ch2[i-1]*cc)%mo;
        for(int i=1;i<=n;i++) haa[i]=haa[i-1]*cc+s[i],haa2[i]=(haa2[i-1]*cc+s[i])%mo;
        for(int i=1;i<=m;i++) hab[i]=hab[i-1]*cc+t[i],hab2[i]=(hab2[i-1]*cc+t[i])%mo;
    }
    inline bool check(int x,int k1,int k2)
    {
        ull hu1=haa[k1+x-1]-ch[x]*haa[k1-1];
        ull hu2=hab[k2+x-1]-hab[k2-1]*ch[x];
        int hu3=(haa2[k1+x-1]-haa2[k1-1]*ch2[x]%mo+mo)%mo;
        int hu4=(hab2[k2+x-1]-hab2[k2-1]*ch2[x]%mo+mo)%mo; 
        return (hu1==hu2)&&(hu3==hu4);
    }
    signed main()
    {
        scanf("%s%s%s",modeyong,s+1,t+1);
        n=strlen(s+1);m=strlen(t+1);
        reverse(t+1,t+m+1);
        malache(0,n);
        for(int i=2;i<=2*n;i+=2)
            f[i/2]=hu[i];
        malache(1,m);zc=max(n,m);
        for(int i=2;i<=2*m;i+=2)
            g[i/2]=hu[i];
        for(int i=1;i<=n;i++) f[i]+=f[i-1];
        for(int i=1;i<=n;i++) f[i]+=f[i-1];
        for(int i=1;i<=m;i++) g[i]+=g[i-1];
        for(int i=1;i<=m;i++) g[i]+=g[i-1];
        get_hash();
        q=read();
        for(int i=1,x,y;i<=q;i++)
        {
            x=read();y=read();
            if(x>n||y>m)
            {
                cout<<"0
    ";
                continue;
            }
            int l=1,r=min(n-x+1,m-y+1),daan=0;
            while(l<=r)
            {
                int mid=(l+r)>>1;
                if(check(mid,x,y)==1)
                    l=mid+1,daan=mid;
                else
                    r=mid-1;
            }
            cout<<f[min(n,x+daan)]+g[min(m,y+daan)]-f[x]-g[y]+daan<<"
    ";
        }
        return 0;
    }
  • 相关阅读:
    linux下给U盘分区&制作文件系统
    迭代器 配接器
    仿函数
    在查询用户的权限的时候 使用左外连接 和 access数据库中左外连接
    C# 想要程序文件移动 而数据保持相对位置
    C# 第三方控件 下面的Item不显示了
    C# 第三方控件 错误 LC-1
    c# 第三方控件 闪退
    access 语句错误
    poj 1469(二分图 最大匹配)
  • 原文地址:https://www.cnblogs.com/betablewaloot/p/12146535.html
Copyright © 2011-2022 走看看