题目描述
传送门
题目大意:给出一个母串和一个模板串,求模板串在母串中的匹配次数。
匹配时,如果用s[i]匹配t[j],那么只要s[i-k]-s[i+k]中有字母与t[j]相同即可算作匹配成功。其中s[i]表示母串的第i位,t[j]表示模板串的第j位。
题解
如果数据范围小的话,这题就是一个DP
f[i][j]=f[i-1][j-1]&mp[i][t[j]]表示母串的第i位匹配到模板串的第j位是否可以匹配上。
其中
mp[i][j]
需要预处理,表示母串的第i位能否匹配字符
j
我们要用
我们计算的时候将所有的字符分开考虑
对于母串来说,如果第
i
位可以匹配当前字符,则
对于模板串来说,如果第
i
位为当前字符,则
令
h[i]
表示到母串的第
i
位,母串
h[k]=∑i=0mf[k−i]∗g[i]
只有
f[k−i]
,
g[i]
同时为1,即匹配上的时候才能产生1的贡献。
上面的式子可以用
FFT
在
O((n+m)log(n+m))
的时间内出解。
然后我们统计每一位所有字符的
h[i]
,如果和为
m
<script type="math/tex" id="MathJax-Element-2637">m</script>则表示在这一位可以匹配上,答案+1
代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#define N 500003
#define pi acos(-1)
using namespace std;
struct data{
double x,y;
data(double X=0,double Y=0) {
x=X,y=Y;
}
}a[N*5],b[N*5];
data operator +(data a,data b){
return data(a.x+b.x,a.y+b.y);
}
data operator -(data a,data b){
return data(a.x-b.x,a.y-b.y);
}
data operator *(data a,data b){
return data(a.x*b.x-a.y*b.y,a.y*b.x+a.x*b.y);
}
int n,m,k,n1,col[N],cl[N],mp[N][5],cost[N];
char s[N];
int calc(char c)
{
if (c=='A') return 1;
if (c=='G') return 2;
if (c=='C') return 3;
if (c=='T') return 4;
}
void clear(data a[N])
{
for (int i=1;i<=n1;i++) a[i].x=0,a[i].y=0;
}
void fft(data x[N],int n,int opt)
{
if (n==1) return;
data l[n>>1],r[n>>1];
for (int i=0;i<n;i+=2)
l[i>>1]=x[i],r[i>>1]=x[i+1];
fft(l,n>>1,opt); fft(r,n>>1,opt);
data wn=data(cos(2*pi/n),sin(2*opt*pi/n));
data w=data(1,0),t;
for (int i=0;i<n>>1;i++,w=wn*w)
t=w*r[i],x[i]=l[i]+t,x[i+(n>>1)]=l[i]-t;
}
int main()
{
freopen("a.in","r",stdin);
scanf("%d%d%d",&n,&m,&k);
scanf("%s",s); n--;
for (int i=0;i<=n;i++) col[i]=calc(s[i]);
scanf("%s",s); m--;
for (int i=0;i<=m;i++) cl[i]=calc(s[m-i]);
for (int i=1;i<=4;i++) {
int nxt=-1;
for (int j=0;j<=n;j++){
if (nxt!=-1&&nxt>=j-k||col[j]==i) mp[j][i]=1;
if (col[j]==i) nxt=j;
}
nxt=-1;
for (int j=n;j>=0;j--) {
if (nxt!=-1&&nxt<=j+k||col[j]==i) mp[j][i]=1;
if (col[j]==i) nxt=j;
}
}
int tot=n+m;
for (n1=1;n1<=tot;n1<<=1);
for (int i=1;i<=4;i++) {
clear(b); clear(a);
for (int j=0;j<=n;j++)
if (mp[j][i]) a[j].x=1;
else a[j].x=0;
for (int j=0;j<=m;j++)
if (cl[j]==i) b[j].x=1;
else b[j].x=0;
fft(a,n1,1); fft(b,n1,1);
for (int j=0;j<=n1;j++) a[j]=a[j]*b[j];
fft(a,n1,-1);
for (int j=0;j<=n;j++)
cost[j]+=(int)(a[j].x/n1+0.5);
}
int ans=0;
for (int i=0;i<=n;i++)
if (cost[i]==m+1) ans++;
printf("%d\n",ans);
}