版权声明:欢迎转载(请附带原链接)ヾ(๑╹◡╹)ノ" https://blog.csdn.net/corsica6/article/details/84871565
传送门: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;
}