题意:给定样本串模式串(只出现4个字母A,C,G,T),求模式串出现多少次。这里匹配定义如下:不一定要严格匹配,在附近k个单位有这个字符都算匹配,可以多个模式串的字符匹配上同一个样本串里的字符。

策爷讲过的大原题啊跪。。。。基本思路是分开考虑每个字母。对于以一个位置i开头,我们考虑这里是否能匹配上,需要处理出这里能匹配的字母个数,如果4个字母分别的匹配个数加起来刚好等于模式串长度,则可以匹配。怎么快速求呢?答案是FFT!

分开考虑每个字母。对于正在考虑的我们标为1,其他为0.模式串也这样表示,然后把它放到位置上去&。还不够,如果我们把模式串倒着,并且用前导零去补位,会发现对于每个位置,可以用一个叉积的式子来表示它的匹配数。。果断FFT啊

时间复杂度O(Sigma*(n+m)log) 其中Sigma是字母种类,对于这道题是4。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define N ((1<<20)+5)
 4 #define eps 0.5
 5 const double PI=acos(-1);
 6 int len,n,m,k,match[N],rev[N],ans;
 7 char st1[N],st2[N],ch[4]={'A','C','G','T'};
 8 struct vec{
 9     double r,i;
10     vec operator + (const vec& w){return (vec){r+w.r,i+w.i};}
11     vec operator - (const vec& w){return (vec){r-w.r,i-w.i};}
12     vec operator * (const vec& w){return (vec){r*w.r-i*w.i,w.i*r+i*w.r};}
13 }A[N],B[N];
14 inline void FFT(vec* x,int f){
15     for(int i=1;i<=len;i++) if(i<rev[i]) swap(x[i],x[rev[i]]);
16     for(int lnow=2;lnow<=len;lnow<<=1){
17         vec w0=(vec){cos(2*PI/lnow*f),sin(2*PI/lnow*f)},t1,t2,w;
18         for(int i=0;i<len;i+=lnow){
19             w=(vec){1,0};
20             for(int j=0;j<lnow/2;j++,w=w*w0){
21                 t1=x[i+j]; t2=w*x[i+j+lnow/2];
22                 x[i+j]=t1+t2; x[i+j+lnow/2]=t1-t2;
23             }
24         }
25     } 
26 }
27 inline int read(){
28     int x=0,f=1; char a=getchar();
29     while(a<'0' || a>'9') {if(a=='-') f=-1; a=getchar();}
30     while(a>='0' && a<='9') x=x*10+a-'0',a=getchar();
31     return x*f;
32 }
33 int main(){
34     n=read(); m=read(); k=read();
35     scanf("%s%s",st1,st2); int t=0; 
36     for(len=1;len<=2*n;len<<=1,t++); t--;
37     for(int i=1;i<=len;i++) rev[i]=(rev[i>>1]>>1)|(i&1?1<<t:0);
38     for(int last,i=0;i<4;i++){
39         for(int j=0;j<=len;j++) A[j]=B[j]=(vec){0,0}; 
40         last=0;
41         for(int j=0;j<n;j++) 
42             if(st1[j]==ch[i]){
43                 for(int t=max(j-k,last);t<=j+k && t<n;t++) A[t].r=1.0;
44                 last=j+k;
45             }
46         for(int j=0;j<m;j++)
47         if(st2[j]==ch[i]) B[len/2-j+1].r=1.0;
48         FFT(A,1); FFT(B,1);
49         for(int j=0;j<=len;j++) A[j]=A[j]*B[j];
50         FFT(A,-1);
51         for(int j=0;j<n;j++)
52         match[j]+=(int)(A[j+len/2].r/len+eps);
53     }
54     for(int i=0;i<n;i++){
55         if(match[i]==m) ans++;
56     }
57     printf("%d\n",ans);
58     return 0;
59 }