题意:给定样本串模式串(只出现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 ",ans); 58 return 0; 59 }