zoukankan      html  css  js  c++  java
  • [CF528D]Fuzzy Search

    https://www.zybuluo.com/ysner/note/1287760

    题面

    给定原串(S)和匹配串(T),允许错开不超过(k)位匹配(即(T)中第(i)位字符可以与(S)([i-k,i+k])中的相同字符匹配)。问(|T|)(|S|)中出现次数。
    字符集大小为(4)

    • (|S|,|T|,kleq2*10^5)

    解析

    在字符串问题上,都有一个通往卷积的套路:把某个字符串翻转。
    这样可以使得两个字符串中,当前对应的字符坐标和均为(|S|+|T|),满足卷积形式。
    对每个字符串分开考虑,设两个多项式(A(x),B(x)):(其中(char)表示当前枚举的字符)

    [A(x)=sum_{i=0}^{|S|-1}(exists charin[i-k,i+k])x^i ]

    [B(x)=sum_{i=0}^{|T|-1}(char==T[x])x^i ]

    两个多项式卷一下,就是这种字符在(|S|)中第(i)个位置上的匹配数。
    最后,如果有位置(4)个字符匹配数之和达到(|T|),就说明形成了一种匹配方案。

    其实这个玩意儿不太好理解。
    (A(x))中第(i)位为(1)(B(x))中第(j)位为(1),则两项相乘将贡献答案,放在(i+m-j+1)位。
    同样放在这一位的答案,只有可能是(i++)(j--)形成的。
    而这样的过程对应的是串的匹配过程(翻转后)。

    还有有人跟我说形成方案的位数(即(i+m-j+1))小于(|S|)。。。我不能理解。。。

    注意字符串起点位置必须是(0)!!!

    #include<iostream>
    #include<cstring>
    #include<cmath>
    #include<cstdio>
    #include<cstdlib>
    #include<algorithm>
    #define ll long long
    #define re register
    #define il inline
    #define cp complex
    #define db double 
    #define fp(i,a,b) for(re int i=a;i<=b;i++)
    #define fq(i,a,b) for(re int i=a;i>=b;i--)
    using namespace std;
    const int N=8e5+100;
    const db pi=acos(-1);
    int n,m,k,l,r[N],lim=1,ans[N/4],Ans;
    char s1[N/4],s2[N/4],id[4]={'A','C','G','T'};
    struct cp
    {
      db x,y;
      il cp(){x=y=0;}
      il cp(re db xx,re db yy){x=xx,y=yy;}
    }a[N],b[N];
    il cp operator + (re cp a,re cp b){return cp(a.x+b.x,a.y+b.y);}
    il cp operator - (re cp a,re cp b){return cp(a.x-b.x,a.y-b.y);}
    il cp operator * (re cp a,re cp b){return cp(a.x*b.x-a.y*b.y,a.x*b.y+a.y*b.x);}
    il void FFT(re cp *A,re int tp)
    {
      fp(i,1,lim-1) if(i<r[i]) swap(A[i],A[r[i]]);
      for(re int mid=1;mid<lim;mid<<=1)
        {
           re cp W(cos(pi/mid),tp*sin(pi/mid));
           for(re int R=mid<<1,j=0;j<lim;j+=R)
           {
             re cp w(1,0);
             for(re int k=0;k<mid;++k,w=w*W)
             {
               re cp x=A[j+k],y=w*A[j+mid+k];
               A[j+k]=x+y;A[j+mid+k]=x-y;
             }
           }
        }
    }
    il ll gi()
    {
      re ll x=0,t=1;
      re char ch=getchar();
      while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
      if(ch=='-') t=-1,ch=getchar();
      while(ch>='0'&&ch<='9') x=x*10+ch-48,ch=getchar();
      return x*t;
    }
    int main()
    {
      n=gi();m=gi();k=gi();
      scanf("%s",s1);scanf("%s",s2);reverse(s2,s2+m);
      while(lim<=n+m) lim<<=1,++l;
      fp(i,1,lim-1) r[i]=(r[i>>1]>>1)|((i&1)<<l-1);
      fp(o,0,3)
      {
        fp(i,0,lim-1) a[i].x=a[i].y=b[i].x=b[i].y=0;
        re int pos=-1e9;
        fp(i,0,n-1)
        {
          if(s1[i]==id[o]) pos=i;
          if(pos>=i-k) a[i].x=1;
        }
        pos=1e9;
        fq(i,n-1,0)
        {
          if(s1[i]==id[o]) pos=i;
          if(pos<=i+k) a[i].x=1;
        }
        fp(i,0,m-1) if(s2[i]==id[o]) b[i].x=1;
        FFT(a,1);FFT(b,1);
        fp(i,0,lim-1) a[i]=a[i]*b[i];
        FFT(a,-1);
        fp(i,0,lim-1) ans[i]+=(int)(a[i].x/lim+0.5);
      }
      fp(i,0,lim-1) if(ans[i]==m) ++Ans;
      printf("%d
    ",Ans);
      return 0;
    }
    
  • 相关阅读:
    【年度总结】——踏雪留痕
    ios提交程序后出现的各种问题
    c++动态库中使用命名空间的问题
    第八章 网络的时代—网络开发(4)
    USB otg 学习笔记
    servlet_3
    Windows server 2012清除并重建SID
    实时监听输入框值变化:oninput & onpropertychange
    JQuery 自动触发事件
    jquery input change事件
  • 原文地址:https://www.cnblogs.com/yanshannan/p/9677618.html
Copyright © 2011-2022 走看看