@ysner
2018-09-19T22:02:35.000000Z
字数 2175
阅读 2116
字符串
FFT/NTT
给定原串和匹配串,允许错开不超过位匹配(即中第位字符可以与中中的相同字符匹配)。问在中出现次数。
字符集大小为。
在字符串问题上,都有一个通往卷积的套路:把某个字符串翻转。
这样可以使得两个字符串中,当前对应的字符坐标和均为,满足卷积形式。
对每个字符串分开考虑,设两个多项式:(其中表示当前枚举的字符)
其实这个玩意儿不太好理解。
设中第位为,中第位为,则两项相乘将贡献答案,放在位。
同样放在这一位的答案,只有可能是且形成的。
而这样的过程对应的是串的匹配过程(翻转后)。
还有有人跟我说形成方案的位数(即)小于。。。我不能理解。。。
注意字符串起点位置必须是!!!
#include<iostream>
#include<cstring>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#define ll long long
#define re register
#define il inline
#define cp complex
#define db double
#define fp(i,a,b) for(re int i=a;i<=b;i++)
#define fq(i,a,b) for(re int i=a;i>=b;i--)
using namespace std;
const int N=8e5+100;
const db pi=acos(-1);
int n,m,k,l,r[N],lim=1,ans[N/4],Ans;
char s1[N/4],s2[N/4],id[4]={'A','C','G','T'};
struct cp
{
db x,y;
il cp(){x=y=0;}
il cp(re db xx,re db yy){x=xx,y=yy;}
}a[N],b[N];
il cp operator + (re cp a,re cp b){return cp(a.x+b.x,a.y+b.y);}
il cp operator - (re cp a,re cp b){return cp(a.x-b.x,a.y-b.y);}
il cp operator * (re cp a,re cp b){return cp(a.x*b.x-a.y*b.y,a.x*b.y+a.y*b.x);}
il void FFT(re cp *A,re int tp)
{
fp(i,1,lim-1) if(i<r[i]) swap(A[i],A[r[i]]);
for(re int mid=1;mid<lim;mid<<=1)
{
re cp W(cos(pi/mid),tp*sin(pi/mid));
for(re int R=mid<<1,j=0;j<lim;j+=R)
{
re cp w(1,0);
for(re int k=0;k<mid;++k,w=w*W)
{
re cp x=A[j+k],y=w*A[j+mid+k];
A[j+k]=x+y;A[j+mid+k]=x-y;
}
}
}
}
il ll gi()
{
re ll x=0,t=1;
re char ch=getchar();
while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
if(ch=='-') t=-1,ch=getchar();
while(ch>='0'&&ch<='9') x=x*10+ch-48,ch=getchar();
return x*t;
}
int main()
{
n=gi();m=gi();k=gi();
scanf("%s",s1);scanf("%s",s2);reverse(s2,s2+m);
while(lim<=n+m) lim<<=1,++l;
fp(i,1,lim-1) r[i]=(r[i>>1]>>1)|((i&1)<<l-1);
fp(o,0,3)
{
fp(i,0,lim-1) a[i].x=a[i].y=b[i].x=b[i].y=0;
re int pos=-1e9;
fp(i,0,n-1)
{
if(s1[i]==id[o]) pos=i;
if(pos>=i-k) a[i].x=1;
}
pos=1e9;
fq(i,n-1,0)
{
if(s1[i]==id[o]) pos=i;
if(pos<=i+k) a[i].x=1;
}
fp(i,0,m-1) if(s2[i]==id[o]) b[i].x=1;
FFT(a,1);FFT(b,1);
fp(i,0,lim-1) a[i]=a[i]*b[i];
FFT(a,-1);
fp(i,0,lim-1) ans[i]+=(int)(a[i].x/lim+0.5);
}
fp(i,0,lim-1) if(ans[i]==m) ++Ans;
printf("%d\n",Ans);
return 0;
}