codeforces 528D. Fuzzy Search (FFT优化DP)

来源:互联网 发布:linux怎么读音是什么 编辑:程序博客网 时间:2024/06/13 22:27

题目描述

传送门

题目大意:给出一个母串和一个模板串,求模板串在母串中的匹配次数。
匹配时,如果用s[i]匹配t[j],那么只要s[i-k]-s[i+k]中有字母与t[j]相同即可算作匹配成功。其中s[i]表示母串的第i位,t[j]表示模板串的第j位。

题解

如果数据范围小的话,这题就是一个DP
f[i][j]=f[i-1][j-1]&mp[i][t[j]]表示母串的第i位匹配到模板串的第j位是否可以匹配上。
其中mp[i][j]需要预处理,表示母串的第i位能否匹配字符j
我们要用FFT,考虑如何构造向量
我们计算的时候将所有的字符分开考虑
对于母串来说,如果第i位可以匹配当前字符,则f[i]=1
对于模板串来说,如果第i 位为当前字符,则g[i]=1
h[i] 表示到母串的第i 位,母串[im+1,i]与模板串 [1,m]匹配可以匹配上多少位,将模式串翻转,然后将h[i]表示成公式就是
h[k]=i=0mf[ki]g[i]
只有f[ki],g[i] 同时为1,即匹配上的时候才能产生1的贡献。
上面的式子可以用FFTO((n+m)log(n+m))的时间内出解。
然后我们统计每一位所有字符的h[i] ,如果和为m则表示在这一位可以匹配上,答案+1

代码

#include<iostream>  #include<cstdio>  #include<algorithm>  #include<cmath>  #include<cstring>  #define N 500003  #define pi acos(-1)  using namespace std;  struct data{      double x,y;      data(double X=0,double Y=0) {          x=X,y=Y;      }  }a[N*5],b[N*5];  data operator +(data a,data b){        return data(a.x+b.x,a.y+b.y);    }    data operator -(data a,data b){        return data(a.x-b.x,a.y-b.y);    }    data operator *(data a,data b){        return data(a.x*b.x-a.y*b.y,a.y*b.x+a.x*b.y);    }    int n,m,k,n1,col[N],cl[N],mp[N][5],cost[N];  char s[N];  int calc(char c)  {      if (c=='A') return 1;      if (c=='G') return 2;      if (c=='C') return 3;      if (c=='T') return 4;  }  void clear(data a[N]){    for (int i=1;i<=n1;i++) a[i].x=0,a[i].y=0;}void fft(data x[N],int n,int opt)  {      if (n==1) return;      data l[n>>1],r[n>>1];      for (int i=0;i<n;i+=2)       l[i>>1]=x[i],r[i>>1]=x[i+1];      fft(l,n>>1,opt); fft(r,n>>1,opt);      data wn=data(cos(2*pi/n),sin(2*opt*pi/n));      data w=data(1,0),t;      for (int i=0;i<n>>1;i++,w=wn*w)       t=w*r[i],x[i]=l[i]+t,x[i+(n>>1)]=l[i]-t;  }  int main()  {      freopen("a.in","r",stdin);    scanf("%d%d%d",&n,&m,&k);      scanf("%s",s); n--;      for (int i=0;i<=n;i++) col[i]=calc(s[i]);      scanf("%s",s); m--;      for (int i=0;i<=m;i++) cl[i]=calc(s[m-i]);      for (int i=1;i<=4;i++) {          int nxt=-1;          for (int j=0;j<=n;j++){              if (nxt!=-1&&nxt>=j-k||col[j]==i) mp[j][i]=1;              if (col[j]==i)  nxt=j;          }          nxt=-1;          for (int j=n;j>=0;j--) {              if (nxt!=-1&&nxt<=j+k||col[j]==i) mp[j][i]=1;              if (col[j]==i)  nxt=j;          }      }      int tot=n+m;     for (n1=1;n1<=tot;n1<<=1);      for (int i=1;i<=4;i++) {          clear(b); clear(a);        for (int j=0;j<=n;j++)            if (mp[j][i]) a[j].x=1;           else a[j].x=0;          for (int j=0;j<=m;j++)           if (cl[j]==i) b[j].x=1;           else b[j].x=0;        fft(a,n1,1); fft(b,n1,1);          for (int j=0;j<=n1;j++) a[j]=a[j]*b[j];          fft(a,n1,-1);          for (int j=0;j<=n;j++)           cost[j]+=(int)(a[j].x/n1+0.5);      }      int ans=0;      for (int i=0;i<=n;i++)       if (cost[i]==m+1) ans++;      printf("%d\n",ans);   }   
0 0