• 【BZOJ】4259: 残缺的字符串 FFT


    【题意】给定长度为m的匹配串B和长度为n的模板串A,求B在A中出现多少次。字符串仅由小写字母和通配符" * "组成,其中通配符可以充当任意一个字符。n<=3*10^5。

    【算法】FFT

    【题解】假设模板串的数组A用0~26代表所有字符,0为通配符,匹配串的数组B同理,那么用表示差异的经典套路:

    $$C_n=sum_{i=0}^{m-1}(A_{n+i}-B_i)^2*A_{n+i}*B_i$$

    那么可以看出$C_n=0$当且仅当$S_A[n,n+m-1]=S_B[0,m-1]$。这里的通配符为0,所以当含有通配符时式子直接为0,即无差异。

    将数组A反转,得到:

    $$C_x=sum_{i=0}^{m-1}(A'_{n-x-i-1}-B_i)^2*A'_{n-x-i-1}*B_i$$

    尝试扩展上届:

    $$C_x=D_{n-x-1}=sum_{i=0}^{n-x-1}(A'_{n-x-i-1}-B_i)^2*A'_{n-x-i-1}*B_i$$

    现在只需要计算Dx了,二项式拆分得到:

    $$D_x=sum_{i=0}^{x}A_{x-i}^3B_i-2A_{x-i}^2B_i^2+A_{x-i}B_i^3$$

    (这里公式不知道A后为什么不能加单引号,不然latex会出错)

    复杂度O(n log n)。

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    const int maxn=1100010,N=300010;
    const double PI=acos(-1);
    int m,n,aa[N],bb[N],d[N];
    char A[N],B[N];
    struct cp{
        double x,y;
        cp(double a,double b){x=a;y=b;}
        cp(){x=y=0;}
        cp operator + (cp a){return cp(x+a.x,y+a.y);}
        cp operator - (cp a){return cp(x-a.x,y-a.y);}
        cp operator * (cp a){return cp(x*a.x-y*a.y,x*a.y+y*a.x);}
    }A1[maxn],A2[maxn],A3[maxn],B1[maxn],B2[maxn],B3[maxn];
    void fft(cp *a,int n,int f){
        int k=0;
        for(int i=0;i<n;i++){
            if(i<k)swap(a[i],a[k]);
            for(int j=n>>1;(k^=j)<j;j>>=1);
        }
        for(int l=2;l<=n;l<<=1){
            int m=l/2;
            cp wn(cos(2*PI*f/l),sin(2*PI*f/l));
            for(cp *p=a;p!=a+n;p+=l){
                cp w(1,0);
                for(int i=0;i<l/2;i++){
                    cp t=w*p[i+m];
                    p[i+m]=p[i]-t;
                    p[i]=p[i]+t;
                    w=w*wn;
                }
            }
        }
        if(f==-1)for(int i=0;i<n;i++)a[i].x/=n;
    }
    int main(){
        scanf("%d%d%s%s",&m,&n,B,A);
        for(int i=0;i<n;i++)aa[n-i-1]=(A[i]=='*'?0:A[i]-'a'+1);
        for(int i=0;i<m;i++)bb[i]=(B[i]=='*'?0:B[i]-'a'+1);
        for(int i=0;i<n;i++)A1[i]=cp(aa[i],0),A2[i]=cp(aa[i]*aa[i],0),A3[i]=cp(aa[i]*aa[i]*aa[i],0);
        for(int i=0;i<m;i++)B1[i]=cp(bb[i],0),B2[i]=cp(bb[i]*bb[i],0),B3[i]=cp(bb[i]*bb[i]*bb[i],0);
        int N=1;while(N<n+m)N<<=1;
        fft(A1,N,1);fft(B1,N,1);
        fft(A2,N,1);fft(B2,N,1);
        fft(A3,N,1);fft(B3,N,1);
        for(int i=0;i<N;i++)A1[i]=A3[i]*B1[i]-cp(2,0)*A2[i]*B2[i]+A1[i]*B3[i];
        fft(A1,N,-1);
        int cnt=0;
        for(int i=0;i<=n-m;i++)if(!((int)(A1[n-1-i].x+0.1)))d[++cnt]=i+1;
        printf("%d
    ",cnt);
        for(int i=1;i<=cnt;i++)printf("%d ",d[i]);
        return 0;
    }
    View Code
  • 相关阅读:
    判断整除(动态规划,递推)
    Apollo 配置详细步骤(Windows环境)
    java的环境变量
    我的C++学习心得
    Maven实战_许晓斌
    深入理解计算机系统--中文版
    http 权威指南 -- http the definitive guide
    看原版英文和译版中文
    python 单元测试框架 pyunit
    在SQL Server 中创建外键
  • 原文地址:https://www.cnblogs.com/onioncyc/p/8858083.html
Copyright © 2020-2023  润新知