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;
    }
  • 相关阅读:
    机器学习(深度学习)
    机器学习(六)
    机器学习一-三
    Leetcode 90. 子集 II dfs
    Leetcode 83. 删除排序链表中的重复元素 链表操作
    《算法竞赛进阶指南》 第二章 Acwing 139. 回文子串的最大长度
    LeetCode 80. 删除有序数组中的重复项 II 双指针
    LeetCode 86 分割链表
    《算法竞赛进阶指南》 第二章 Acwing 138. 兔子与兔子 哈希
    《算法竞赛进阶指南》 第二章 Acwing 137. 雪花雪花雪花 哈希
  • 原文地址:https://www.cnblogs.com/betablewaloot/p/12146535.html
Copyright © 2011-2022 走看看