• [BZOJ4259]残缺的字符串


    Description:

    给定两个带通配符的串,求可能出现几次匹配,以及这些匹配位置

    Hint:

    (n le 3*10^5)

    Solution:

    定义匹配函数 (P(x)=sum_{i=x}^{x+m}(S1[i]-S2[i])^2*S1[i]*S2[i]​)

    展开的式子太长,有时间再放

    大概是一堆字符串卷积

    翻转后FFT即可

    #include <map>
    #include <set>
    #include <stack>
    #include <cmath>
    #include <queue>
    #include <cstdio>
    #include <cstring>
    #include <cstdlib>
    #include <iostream>
    #include <algorithm>
    #define ls p<<1 
    #define rs p<<1|1
    using namespace std;
    typedef long long ll;
    const int mxn=2e6+5;
    const double PI=acos(-1);
    int n,m,l,tot,lim=1,a[mxn],b[mxn],r[mxn],q[mxn];
    ll s[mxn];
    char s1[mxn],s2[mxn];
    inline int read() {
        char c=getchar(); int x=0,f=1;
        while(c>'9'||c<'0') {if(c=='-') f=-1;c=getchar();}
        while(c<='9'&&c>='0') {x=(x<<3)+(x<<1)+(c&15);c=getchar();}
        return x*f;
    }
    inline int chkmax(register int &x,register int y) {if(x<y) x=y;}
    inline int chkmin(register int &x,register int y) {if(x>y) x=y;}
    
    struct ed {
        int to,nxt;
    }t[mxn<<1];
    
    struct cp {
        double x,y;
        cp (double xx=0,double yy=0) {x=xx;y=yy;}
        friend cp operator + (cp a,cp b) {
            return cp(a.x+b.x,a.y+b.y);
        }
        friend cp operator - (cp a,cp b) {
            return cp(a.x-b.x,a.y-b.y);
        }
        friend cp operator * (cp a,cp b) {
            return cp(a.x*b.x-a.y*b.y,a.x*b.y+a.y*b.x);
        }
    }A[mxn],B[mxn],C[mxn];
    
    void FFT(cp *p,register int opt)
    {
        for(register int i=0;i<lim;++i) 
            if(i<r[i]) swap(p[i],p[r[i]]);
        for(register int mid=1;mid<lim;mid<<=1) {
            cp wn=cp(cos(PI/mid),opt*sin(PI/mid));
            for(register int len=mid<<1,j=0;j<lim;j+=len) {
                cp w=cp(1,0);
                for(register int k=0;k<mid;++k,w=w*wn) {
                    cp x=p[j+k],y=w*p[j+mid+k];
                    p[j+k]=x+y; p[j+mid+k]=x-y;
                }
            }
        }
    }
    
    int main()
    {
        scanf("%d%d%s%s",&m,&n,s1,s2);
        for(register int i=0,j=m-1;i<j;++i,--j) swap(s1[i],s1[j]);
        for(register int i=0;i<m;++i) if(s1[i]!='*') a[i]=s1[i]-'a'+1;
        for(register int i=0;i<n;++i) if(s2[i]!='*') b[i]=s2[i]-'a'+1;
        while(lim<=n+m) ++l,lim<<=1;
        for(register int i=0;i<lim;++i) 
            r[i]=(r[i>>1]>>1)|((i&1)<<(l-1));
        for(register int i=0;i<=lim;++i) 
            A[i]=cp(a[i]*a[i]*a[i],0),B[i]=cp(b[i],0);
        FFT(A,1); FFT(B,1); 
        for(register int i=0;i<=lim;++i) C[i]=A[i]*B[i];
        FFT(C,-1);
        for(register int i=0;i<=lim;++i) s[i]+=(ll)(C[i].x/lim+0.5);
        for(register int i=0;i<=lim;++i) 
            A[i]=cp(a[i],0),B[i]=cp(b[i]*b[i]*b[i],0);
        FFT(A,1); FFT(B,1);
        for(register int i=0;i<=lim;++i) C[i]=A[i]*B[i];
        FFT(C,-1);
        for(register int i=0;i<=lim;++i) s[i]+=(ll)(C[i].x/lim+0.5);
        for(register int i=0;i<=lim;++i)
            A[i]=cp(a[i]*a[i],0),B[i]=cp(b[i]*b[i],0);
        FFT(A,1); FFT(B,1); 
        for(register int i=0;i<=lim;++i) C[i]=A[i]*B[i];
        FFT(C,-1);
        for(register int i=0;i<=lim;++i) s[i]-=2*(ll)(C[i].x/lim+0.5);
        for(register int i=m-1;i<n;++i) if(s[i]==0) q[++tot]=i-m+2;
        printf("%d
    ",tot);
        for(register int i=1;i<=tot;++i) printf("%d ",q[i]);
        return 0;
    }
    
    
  • 相关阅读:
    Markdown示例
    初识Markdown
    Ubuntu源整理
    Vi编辑器入门
    Ubuntu,Linux入门系统
    [其他]volatile 关键字
    Qt5:随窗口大小变化背景图片自动缩放的实现
    Qt5:不规则按钮的实现---通过贴图实现
    windows编程:创建DLL
    [转]Firefox拦截12306订票网站的解决办法
  • 原文地址:https://www.cnblogs.com/list1/p/10504685.html
Copyright © 2020-2023  润新知