[CF528D]Fuzzy Search(FFT)

看起来就有点像fft处理带通配符的字符串匹配问题。

AGCT四种字符分类讨论。例如当前匹配A字符,对于S串,把能匹配A的位置记为1,否则为0;对于T串,把A的位置记为1,否则为0。然后还是像通配符问题一样反转T串,用fft加速。这样,对于某一匹配起始位置,能成功匹配的A就会对该位置提供1的贡献。四种字符都做完后,贡献和等于T串长度就位置就是匹配成功的的位置了。

#include<cstdio>
#include<cmath>
#include<cstring>
#include<complex>
#include<algorithm>
#define cp complex<double>
using namespace std;
const int N=200010,M=525000;
const double PI=acos(-1);
char s1[N],s2[N];
int n,n1,n2,k,flag[N],ans,rev[M],lim,tot[N];
cp omg[M],inv[M],a1[M],b1[M];
inline void fft(cp* a,cp* w){
	for(int i=0;i<n;++i)if(i<rev[i])swap(a[i],a[rev[i]]);
	for(int m=1,l=2;l<=n;m=l,l<<=1){
		for(int i=0;i<n;i+=l)
			for(int j=0;j<m;++j){cp tmp=w[n/l*j]*a[i+j+m];a[i+j+m]=a[i+j]-tmp,a[i+j]+=tmp;}
	}
}
int main(){
	scanf("%d%d%d",&n1,&n2,&k),scanf("%s",s1),scanf("%s",s2);
	n=1;while(n<n1+n2)n<<=1;
	lim=0;while((1<<lim)<n)++lim;
	for(int t=0,i=0;i<n;++i,t=0){
		for(int j=0;j<lim;++j)if((1<<j)&i)t|=1<<(lim-j-1);
		rev[i]=t,rev[t]=i;
	}
	for(int i=0;i<n;++i)omg[i]=cp(cos(2*PI*i/n),sin(2*PI*i/n)),inv[i]=conj(omg[i]);
	memset(tot,0,sizeof tot);
	//A
	for(int i=0;i<n;++i)a1[i]=cp(0,0);
	for(int j,i=0;i<n1;++i)
		if(s1[i]=='A'){
			a1[i].real(1),j=i-1;
			while(i-j<=k&&j>=0&&s1[j]!='A'&&a1[j].real()==0)a1[j].real(1),--j;
			j=i+1;
			while(j-i<=k&&j<n1&&s1[j]!='A')a1[j].real(1),++j;
		}
	for(int i=0;i<n2;++i)b1[n2-i-1]=(s2[i]=='A')?cp(1,0):cp(0,0);
	for(int i=n2;i<n;++i)b1[i]=cp(0,0);
	fft(a1,omg),fft(b1,omg);
	for(int i=0;i<n;++i)a1[i]*=b1[i];
	fft(a1,inv);
	for(int i=n2-1;i<n1;++i)tot[i-n2+1]+=(int)(a1[i].real()/n+0.5);
	//G
	for(int i=0;i<n;++i)a1[i]=cp(0,0);
	for(int j,i=0;i<n1;++i)
		if(s1[i]=='G'){
			a1[i].real(1),j=i-1;
			while(i-j<=k&&j>=0&&s1[j]!='G'&&a1[j].real()==0)a1[j].real(1),--j;
			j=i+1;
			while(j-i<=k&&j<n1&&s1[j]!='G')a1[j].real(1),++j;
		}
	for(int i=0;i<n2;++i)b1[n2-i-1]=(s2[i]=='G')?cp(1,0):cp(0,0);
	for(int i=n2;i<n;++i)b1[i]=cp(0,0);
	fft(a1,omg),fft(b1,omg);
	for(int i=0;i<n;++i)a1[i]*=b1[i];
	fft(a1,inv);
	for(int i=n2-1;i<n1;++i)tot[i-n2+1]+=(int)(a1[i].real()/n+0.5);
	//C
	for(int i=0;i<n;++i)a1[i]=cp(0,0);
	for(int j,i=0;i<n1;++i)
		if(s1[i]=='C'){
			a1[i].real(1),j=i-1;
			while(i-j<=k&&j>=0&&s1[j]!='C'&&a1[j].real()==0)a1[j].real(1),--j;
			j=i+1;
			while(j-i<=k&&j<n1&&s1[j]!='C')a1[j].real(1),++j;
		}
	for(int i=0;i<n2;++i)b1[n2-i-1]=(s2[i]=='C')?cp(1,0):cp(0,0);
	for(int i=n2;i<n;++i)b1[i]=cp(0,0);
	fft(a1,omg),fft(b1,omg);
	for(int i=0;i<n;++i)a1[i]*=b1[i];
	fft(a1,inv);
	for(int i=n2-1;i<n1;++i)tot[i-n2+1]+=(int)(a1[i].real()/n+0.5);
	//T
	for(int i=0;i<n;++i)a1[i]=cp(0,0);
	for(int j,i=0;i<n1;++i)
		if(s1[i]=='T'){
			a1[i].real(1),j=i-1;
			while(i-j<=k&&j>=0&&s1[j]!='T'&&a1[j].real()==0)a1[j].real(1),--j;
			j=i+1;
			while(j-i<=k&&j<n1&&s1[j]!='T')a1[j].real(1),++j;
		}
	for(int i=0;i<n2;++i)b1[n2-i-1]=(s2[i]=='T')?cp(1,0):cp(0,0);
	for(int i=n2;i<n;++i)b1[i]=cp(0,0);
	fft(a1,omg),fft(b1,omg);
	for(int i=0;i<n;++i)a1[i]*=b1[i];
	fft(a1,inv);
	for(int i=n2-1;i<n1;++i)tot[i-n2+1]+=(int)(a1[i].real()/n+0.5);
	ans=0;
	for(int i=0;i<=n1-n2;++i)if(tot[i]==n2)++ans;
	printf("%d",ans);
	return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值