zoukankan      html  css  js  c++  java
  • Codeforces 528D Fuzzy Search(FFT)

    【题目链接】 http://codeforces.com/problemset/problem/528/D

    【题目大意】

      给出一个母串,和一个子串,子串允许模糊匹配,模糊匹配的意思就是
      在母串一个范围内如果出现该位置的字符,就当匹配成功,求子串在母串中出现次数。

    【题解】

      寻找子串是否在母串中出现,只要看逆子串和母串的卷积,
      如果一个位置的卷积答案是等于m的那么就匹配,即子串出现一次。
      根据题目条件,我们发现
      子串可以匹配母串范围内的字符也就是子串在母串的某个位置可以有多个匹配满足
      也就是求柔性字符串匹配。
      对于柔性字符串匹配来说,母串的同一个位置可以是多个字符,
      因此我们将其单独拆开来,对于每个字符求出一个匹配数组,
      将这个数组和子串做卷积运算,最后累积答案,最终答案为m的话,就是子串出现了一次
      最后计算答案数组中等于m的数量,就是匹配的次数
      这样就能够解决柔性匹配问题。

    【代码】

    #include <cstdio>
    #include <cmath>
    #include <algorithm>
    #include <cstring> 
    using namespace std;
    typedef long long LL;
    const int N=524300;
    int pos[N],nxt[4],pre[4],mp[N][4],c[N],num[N],n,m,k;
    char s[N],t[N];
    int Tr(char c){
        if(c=='A')return 0;
        if(c=='C')return 1;
        if(c=='G')return 2;
        if(c=='T')return 3;
    }
    namespace FFT{
        struct comp{
            double r,i;
            comp(double _r=0,double _i=0):r(_r),i(_i){}
            comp operator +(const comp&x){return comp(r+x.r,i+x.i);}
            comp operator -(const comp&x){return comp(r-x.r,i-x.i);}
            comp operator *(const comp&x){return comp(r*x.r-i*x.i,i*x.r+r*x.i);}
            comp conj(){return comp(r,-i);}
        }A[N],B[N];
        const double pi=acos(-1.0);
        void FFT(comp a[],int n,int t){
            for(int i=1;i<n;i++)if(pos[i]>i)swap(a[i],a[pos[i]]);
            for(int d=0;(1<<d)<n;d++){
                int m=1<<d,m2=m<<1;
                double o=pi*2/m2*t;
                comp _w(cos(o),sin(o));
                for(int i=0;i<n;i+=m2){
                    comp w(1,0);
                    for(int j=0;j<m;j++){
                        comp& A=a[i+j+m],&B=a[i+j],t=w*A;
                        A=B-t;
                        B=B+t;
                        w=w*_w;
                    }
                }
            }if(t==-1)for(int i=0;i<n;i++)a[i].r/=n;
        }
        void mul(int n,int m,int k,int x){
            int i,j;
            for(i=0;i<k;i++)A[i]=comp(mp[i][x],i<m?Tr(t[m-i-1])==x:0);
            j=__builtin_ctz(k)-1;
            for(int i=0;i<k;i++){pos[i]=pos[i>>1]>>1|((i&1)<<j);} 
            FFT(A,k,1);
            for(int i=0;i<k;i++){
                j=(k-i)&(k-1);
                B[i]=(A[i]*A[i]-(A[j]*A[j]).conj())*comp(0,-0.25);
            }FFT(B,k,-1);
            for(int i=0;i<k;i++)c[i]+=(int)(B[i].r+0.5);
        }
    }
    int main(){
        scanf("%d%d%d%s%s",&n,&m,&k,s,t);
        int N=1,ans=0;; while(N<n+m-1)N<<=1;
        memset(pre,-1,sizeof(pre));
        memset(nxt,-1,sizeof(nxt));
        for(int i=0;i<n;i++){
            int x=Tr(s[i]);
            mp[i][x]=1;
            for(int j=0;j<4;j++)if(~pre[j]&&i-pre[j]<=k)mp[i][j]=1;
            pre[x]=i;
        }
        for(int i=n-1;i>=0;i--){
        	int x=Tr(s[i]);
            for(int j=0;j<4;j++)if(~nxt[j]&&nxt[j]-i<=k)mp[i][j]=1;
            nxt[x]=i;
        }for(int i=0;i<4;i++)FFT::mul(n,m,N,i);
        for(int i=m-1;i<n;i++)if(c[i]==m)ans++;
        printf("%d
    ",ans);
        return 0;
    }
    

      

  • 相关阅读:
    JVM 综述
    看 Netty 在 Dubbo 中如何应用
    Netty 心跳服务之 IdleStateHandler 源码分析
    Netty 高性能之道
    Netty 解码器抽象父类 ByteToMessageDecoder 源码解析
    Netty 源码剖析之 unSafe.write 方法
    Netty 出站缓冲区 ChannelOutboundBuffer 源码解析(isWritable 属性的重要性)
    Netty 源码剖析之 unSafe.read 方法
    Netty 内存回收之 noCleaner 策略
    Netty 源码阅读的思考------耗时业务到底该如何处理
  • 原文地址:https://www.cnblogs.com/forever97/p/codeforces528d.html
Copyright © 2011-2022 走看看