题目描述
题解:
这题是字符串匹配的加强版。
我们可以先预处理出S串的每一个位置能放那些字母。
然后我们考虑对于每一种字母分开来处理。
假设处理字母k。
对于S中的每一位,有可以放这个字母k和不能放两种情况。
对于T中的每一位,有是k和不是k两种情况。
那么对于这个字母,如果S和T的某一位不能匹配只有一种情况:S没有k,而T有k。
我们考虑用FFT来解决字符串的匹配问题。
那么我们可以考虑如果S的某一位有k,就赋0,否则赋1;T是k,就赋1,否则赋0。
假设S,T分别长n和m,这样我们求的就是:
∑
i
=
1
m
S
x
+
i
T
i
\sum_{i=1}^mS_{x+i}T_i
i=1∑mSx+iTi
那么我们可以倒一倒T,就变成了卷积的形式。直接FFT四次即可。
代码如下:
#include<bits/stdc++.h>
using namespace std;
const int maxn=200005;
int n,m,k,hsh[5],S[maxn],T[maxn],ans[maxn][4];
bool pd[maxn][4];
inline int read(){
char ch=getchar();
while (ch!='A'&&ch!='C'&&ch!='G'&&ch!='T') ch=getchar();
if (ch=='A') return 0;
else if (ch=='C') return 1;
else if (ch=='G') return 2;
else return 3;
}
void prework(){
int l=0,r=-1;
for (int i=0;i<=n;i++){
while (l<i-k) hsh[S[l]]--,l++;
while (r<i+k&&r<n) r++,hsh[S[r]]++;
for (int j=0;j<4;j++)
if (hsh[j]) pd[i][j]=1; else pd[i][j]=0;
}
}
namespace FFT{
const int maxm=(1<<19)+5;
const double Pi=acos(-1.0);
int R[maxm],limn,p[maxm];
struct comx{
double x,y;
comx(double xx=0,double yy=0) {x=xx,y=yy;}
comx operator +(const comx b){return comx(x+b.x,y+b.y);}
comx operator -(const comx b){return comx(x-b.x,y-b.y);}
comx operator *(const comx b){return comx(x*b.x-y*b.y,x*b.y+y*b.x);}
}a[maxm],b[maxm],w[maxm];
void fft(comx *a,int lim){
for (int i=0;i<lim;i++)
if (R[i]>i) swap(a[i],a[R[i]]);
for (int t=lim>>1,d=1;d<lim;d<<=1,t>>=1)
for (int i=0;i<lim;i+=(d<<1))
for (int j=0;j<d;j++){
comx p=w[t*j]*a[i+j+d];
a[i+j+d]=a[i+j]-p,a[i+j]=a[i+j]+p;
}
}
void pre(int x){
int L=0; limn=1;
while (limn<=n+m) limn<<=1,L++;
for (int i=0;i<limn;i++){
a[i].x=a[i].y=b[i].x=b[i].y=0.0;
R[i]=((R[i>>1]>>1)|((i&1)<<(L-1)));
w[i]=comx(cos(2.0*Pi/limn*i),sin(2.0*Pi/limn*i));
}
for (int i=0;i<=n;i++) if (pd[i][x]==1) a[i].x=0; else a[i].x=1;
for (int i=0;i<=m;i++) if (T[i]==x) b[m-i].x=1; else b[m-i].x=0;
}
void solve(int x){
pre(x);
fft(a,limn); fft(b,limn);
for (int i=0;i<limn;i++) a[i]=a[i]*b[i],w[i].y=-w[i].y;
fft(a,limn);
for (int i=0;i<limn;i++) w[i].y=-w[i].y,a[i].x/=limn;
memset(p,0,sizeof(p));
for (int i=0;i<=n+m+1;i++) p[i]=(int)(a[i].x+0.5);
for (int i=m;i<=n;i++) if (p[i]==0) ans[i][x]=0; else ans[i][x]=1;
}
}
int main(){
scanf("%d%d%d",&n,&m,&k);
for (int i=0;i<n;i++) S[i]=read();
for (int i=0;i<m;i++) T[i]=read();
n--,m--;
prework();
for (int i=0;i<4;i++) FFT::solve(i);
int sum=0;
for (int i=m;i<=n;i++)
if (ans[i][0]==0&&ans[i][1]==0&&ans[i][2]==0&&ans[i][3]==0) sum++;
printf("%d\n",sum);
return 0;
}