@ysner
2018-09-19T14:02:35.000000Z
字数 2175
阅读 2676
字符串 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;}
