51nod 1565 模糊搜索

来源:互联网 发布:英雄无敌3mac版 编辑:程序博客网 时间:2024/06/07 01:45

有两个基因串S和T,他们只包含AGCT四种字符。现在你要找出T在S中出现了几次。

有一个门限值k≥0TS的第i(1≤i≤|S|-|T|+1)个位置中出现的条件如下:把T的开头和S的第i个字符对齐,然后T中的每一个字符能够在S中找到一样的,且位置偏差不超过k的,那么就认为TS的第i个位置中出现。也就是说对于所有的 j (1≤j≤|T|),存在一个 p (1≤p≤|S|),使得|(i+j-1)-p|≤k [p]=T[j]都成立。

例如,根据这样的定义"ACAT"出现在"AGCAATTCAT"的第2,3和6的位置。


如果k=0,那么这个就是经典的字符串匹配问题。

现在给定门限和两个基因串S,T,求出T在S中出现的次数。


Input
单组测试数据。第一行有三个整数 |S|,|T|,k (1≤|T|≤|S|≤200000, 0≤k≤200000),表示S的长度,T的长度,门限值。第二行给出基因串S。第三行给出基因串T。两个串都只包含大写字母'A', 'T', 'G' 和'C'。
Output
输出一个整数,表示T在S中出现的次数。
Input示例
样例输入110 4 1AGCAATTCATACAT
Output示例
样例输出13
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

FFT+思路~

一共只有4种字符,所以我们把这四种分开匹配,再用&把所有答案综合起来。

因为是模糊匹配,所以在[x-k,x+k]范围内都是可以模糊地计算到x上的。所以我们把每个x的左右k位都划分成1,这样就能匹配到[x-k,x+k]的范围内了。

然后我们把b反向,用4次FFT,检验匹配是否可行。

这次写FFT我学了自己开struct表示complex的方法,如果用complex的话估计就过不了了~

数组要开大!

我的代码常数巨大,1s卡过……所以如果发现T掉了1个点,再交一次就能过辣。


#include<cstdio>#include<cstring>#include<iostream>#include<cmath>using namespace std;#define pi acos(-1)int n,m,n1,m1,r[800001],l,c[800001],id[128],A[4][800001],B[4][800001],ans[800001],totans,k;char s[800001]; struct E{double a,b;E() {}E(double u,double v):a(u),b(v) {}E operator + (const E&u) const {return E(a+u.a,b+u.b);}E operator - (const E&u) const {return E(a-u.a,b-u.b);}E operator * (const E&u) const {return E(a*u.a-b*u.b,a*u.b+b*u.a);}E operator ! () {return E(a,-b);}}a[800001],b[800001];void fft(E *u,int v){for(int i=0;i<n;i++) if(r[i]>i) swap(u[r[i]],u[i]);for(int i=1;i<n;i<<=1){E wn(cos(pi/i),sin(pi/i)*v);for(int j=0;j<n;j+=(i<<1)){E w(1,0);for(int k=0;k<i;k++,w=w*wn){E x=u[j+k],y=u[i+j+k]*w;u[j+k]=x+y;u[i+j+k]=x-y;}}}if(v==-1) for(int i=0;i<n;i++) u[i].a/=n;}int main(){id['A']=0;id['T']=1;id['C']=2;id['G']=3;scanf("%d%d%d",&n1,&m1,&k);scanf("%s",s);for(int i=0;i<n1;i++){int kk=id[s[i]];A[kk][i]=1;for(int j=i+1;j<=min(n1-1,i+k);j++)  if(id[s[j]]==kk) break;  else A[kk][j]=1;for(int j=i-1;j>=max(0,i-k);j--)  if(A[kk][j]) break;  else A[kk][j]=1;}scanf("%s",s);for(int i=0;i<m1;i++) B[id[s[i]]][m1-i-1]=1;m=n1+m1;for(int i=m1-1;i<=m-2;i++) ans[i]=1;for(n=1;n<=m;n<<=1) l++;for(int i=0;i<n;i++) r[i]=(r[i>>1]>>1)|((i&1)<<(l-1));for(int k=0;k<4;k++){memset(a,0,sizeof(a));memset(b,0,sizeof(b));for(int i=0;i<n1;i++) a[i]=E(A[k][i],0);for(int i=0;i<m1;i++) b[i]=E(B[k][i],0);fft(a,1);fft(b,1);for(int i=0;i<=n;i++) a[i]=a[i]*b[i];fft(a,-1);for(int i=0;i<=n;i++) c[i]=(int)(a[i].a+0.5);int now=0;for(int i=0;i<m1;i++) now+=B[k][i];for(int i=m1-1;i<=m-2;i++) ans[i]&=(c[i]==now);}for(int i=m1-1;i<=m-2;i++) totans+=ans[i];printf("%d\n",totans);return 0;}


原创粉丝点击