【Codeforces】528D. Fuzzy Search-FFT&模式串匹配
阿新 • • 發佈:2019-01-03
傳送門:cf528D
題解
按照模式串匹配套路,不妨設 分別表示與位置 距離不超過 的位置上有/沒有 ,並將 翻轉。
但發現式子中還是有 不好卷積,且 位置的值實際上只與 對應的字母有關。而字符集大小又很小。。。
所以考慮依次列舉當前匹配的字元,如果所有情況都滿足條件那麼就匹配上了。
程式碼
#include<bits/stdc++.h>
#define ld long double
using namespace std;
const int M=2e5+10,N=2e6+100;
const ld pi=acos(-1.0);
int n,m,K,c[M],ans,ss[M];
int rv[N],len,L;
char s[M],t[M];
struct cc{
ld r,i;
cc(ld r_=0,ld i_=0):r(r_),i(i_){};
cc operator +(const cc &A){return cc(r+A.r,i+A.i);}
cc operator -(const cc &A){return cc(r-A.r,i-A.i);}
cc operator *(const cc &A){return cc(r*A.r-i*A.i,i*A.r+A.i*r);}
cc operator /(const ld &A){return cc(r/A,i/A);}
inline cc conj(){return cc(r,-i);}
}f[N],g[N],rp;
inline void fft(cc *e,int pr)
{
int i,j,k;cc ix,iy,ori,pd;
for(i=1;i<len;++i) if(i<rv[i]) swap(e[i],e[rv[i]]);
for(i=1;i<len;i<<=1){
ori=cc(cos(pi/i),pr*sin(pi/i));
for(j=0;j<len;j+=(i<<1)){
pd=cc(1,0);
for(k=0;k<i;++k,pd=pd*ori){
ix=e[j+k];iy=pd*e[i+j+k];
e[j+k]=ix+iy;e[i+j+k]=ix-iy;
}
}
}
if(pr==1) return;
for(i=0;i<len;++i) e[i]=e[i]/(ld)len;
}
inline void ck(int alp)
{
int i,j;memset(c,0,sizeof(c));
for(i=0;i<m;++i) f[i].i=(t[i]==alp)?1.0:0;
for(i=m;i<len;++i) f[i].i=0;
for(i=0;i<n;++i) if(s[i]==alp) c[max(0,i-K)]++,c[min(n,i+K+1)]--;
for(i=0;i<n;++i){f[i].r=(c[i]>0)?0.0:1.0;c[i+1]+=c[i];}
for(i=n;i<len;++i) f[i].r=0;
fft(f,1);rp=cc(0,0.25);
for(i=0;i<len;++i){
j=(len-i)&(len-1);
g[i]=((f[j]*f[j]).conj()-f[i]*f[i])*rp;
}
fft(g,-1);
for(i=m-1;i<n;++i) ss[i]+=(int)(g[i].r+0.5);
}
int main(){
int i;scanf("%d%d%d%s%s",&n,&m,&K,s,t);
reverse(t,t+m);
for(len=1;len<n+m;len<<=1) L++;
for(i=1;i<len;++i) rv[i]=((rv[i>>1]>>1)|((i&1)<<(L-1)));
ck('A');ck('T');ck('G');ck('C');
for(i=m-1;i<n;++i) if(ss[i]==0) ans++;
printf("%d",ans);
return 0;
}