zoukankan      html  css  js  c++  java
  • BZOJ4259:残缺的字符串——题解

    https://www.lydsy.com/JudgeOnline/problem.php?id=4259

    很久很久以前,在你刚刚学习字符串匹配的时候,有两个仅包含小写字母的字符串A和B,其中A串长度为m,B串长度为n。可当你现在再次碰到这两个串时,这两个串已经老化了,每个串都有不同程度的残缺。
    你想对这两个串重新进行匹配,其中A为模板串,那么现在问题来了,请回答,对于B的每一个位置i,从这个位置开始连续m个字符形成的子串是否可能与A串完全匹配?

    跟随胡神犇的步伐先把前置技能学了。

    参考:https://www.cnblogs.com/clrs97/p/4814499.html

    kmp是不行的,而作为一道套路题,我们有一定的套路:暴力匹配!

    先默认字符串是以0开头的,方便我们后来FFT。

    设dis(A,B)=(A-B)*[A!='*']*[B!='*']表示了AB字符是否相等,如果相等则答案为0。

    于是我们把*字符看做0,则直接变成dis(A,B)=(A-B)AB。

    设f[i]为B串以i为终点,往前与A匹配是否能匹配上。

    显然就是dis累加的过程,只要最终f[i]=0就说明i-n+2是一个合法解。

    然后你就会发现这个dis累加拆开之后很像卷积啊。

    于是把A数组倒过来然后后面补齐0(即*字符),你就会发现实际上这就是三个卷积。

    于是我们(不)愉快的写了个FFT并且AC。

    (式子推导就看参考吧……心情不好不想写数学公式)

    #include<map>
    #include<cmath>
    #include<stack>
    #include<queue>
    #include<cstdio>
    #include<cctype>
    #include<vector>
    #include<cstdlib>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    typedef double dl;
    const dl pi=acos(-1.0);
    const dl eps=0.5;
    const int N=2e6+5;
    struct complex{
        dl x,y;
        complex(dl xx=0.0,dl yy=0.0){
        x=xx;y=yy;
        }
        complex operator +(const complex &b)const{
        return complex(x+b.x,y+b.y);
        }
        complex operator -(const complex &b)const{
        return complex(x-b.x,y-b.y);
        }
        complex operator *(const complex &b)const{
        return complex(x*b.x-y*b.y,x*b.y+y*b.x);
        }
    };
    void FFT(complex a[],int n,int on){
        for(int i=1,j=n>>1;i<n-1;i++){
        if(i<j)swap(a[i],a[j]);
        int k=n>>1;
        while(j>=k){j-=k;k>>=1;}
        if(j<k)j+=k;
        }
        for(int i=2;i<=n;i<<=1){
        complex res(cos(-on*2*pi/i),sin(-on*2*pi/i));
        for(int j=0;j<n;j+=i){
            complex w(1,0);
            for(int k=j;k<j+i/2;k++){
            complex u=a[k],t=w*a[k+i/2];
            a[k]=u+t;a[k+i/2]=u-t;
            w=w*res;
            }
        }
        }
        if(on==-1)
        for(int i=0;i<n;i++)a[i].x/=n;
    }
    int n,m,a[N],b[N];
    complex f[N],A[N],B[N];
    char s1[N],s2[N];
    int main(){
        scanf("%d%d%s%s",&n,&m,s1,s2);
        for(int i=0,j=n-1;i<j;i++,j--)swap(s1[i],s1[j]);
        for(int i=0;i<n;i++){
        if(s1[i]!='*')a[i]=s1[i]-'a'+1;
        else a[i]=0;
        }
        for(int i=0;i<m;i++){
        if(s2[i]!='*')b[i]=s2[i]-'a'+1;
        else b[i]=0;
        }
        int len=1;
        while(len<m)len<<=1;
    
        for(int i=0;i<len;i++)
        A[i]=complex(a[i]*a[i]*a[i],0),B[i]=complex(b[i],0);
        FFT(A,len,1);FFT(B,len,1);
        for(int i=0;i<len;i++)f[i]=f[i]+A[i]*B[i];
        
        for(int i=0;i<len;i++)
        A[i]=complex(a[i]*a[i],0),B[i]=complex(b[i]*b[i],0);
        FFT(A,len,1);FFT(B,len,1);
        for(int i=0;i<len;i++)f[i]=f[i]-A[i]*B[i]*complex(2,0);
    
        for(int i=0;i<len;i++)
        A[i]=complex(a[i],0),B[i]=complex(b[i]*b[i]*b[i],0);
        FFT(A,len,1);FFT(B,len,1);
        for(int i=0;i<len;i++)f[i]=f[i]+A[i]*B[i];
    
        FFT(f,len,-1);
        int ans=0;
        for(int i=n-1;i<m;i++)if(f[i].x<eps)ans++;
        printf("%d
    ",ans);
        if(ans){
        for(int i=n-1;i<m;i++)if(f[i].x<eps)printf("%d ",i-n+2);
        puts("");
        }
        return 0;
    }

    +++++++++++++++++++++++++++++++++++++++++++

     +本文作者:luyouqi233。               +

     +欢迎访问我的博客:http://www.cnblogs.com/luyouqi233/+

    +++++++++++++++++++++++++++++++++++++++++++

  • 相关阅读:
    第八周上机作业
    第七周课后作业
    第七周上机作业
    第六周课后作业
    第六周上机
    第九周JAVA
    第八周JAVA
    第8次JAVA作业
    第七周JAVA
    第7周JAVA
  • 原文地址:https://www.cnblogs.com/luyouqi233/p/9162417.html
Copyright © 2011-2022 走看看