Codeforces 528 D. Fuzzy Search

版权声明:原创文章,转载要注明作者哦 https://blog.csdn.net/DYT_B/article/details/85299906

题目描述

题解:

这题是字符串匹配的加强版。
我们可以先预处理出S串的每一个位置能放那些字母。
然后我们考虑对于每一种字母分开来处理。
假设处理字母k。
对于S中的每一位,有可以放这个字母k和不能放两种情况。
对于T中的每一位,有是k和不是k两种情况。
那么对于这个字母,如果S和T的某一位不能匹配只有一种情况:S没有k,而T有k。
我们考虑用FFT来解决字符串的匹配问题。
那么我们可以考虑如果S的某一位有k,就赋0,否则赋1;T是k,就赋1,否则赋0。
假设S,T分别长n和m,这样我们求的就是:
i = 1 m S x + i T i \sum_{i=1}^mS_{x+i}T_i
那么我们可以倒一倒T,就变成了卷积的形式。直接FFT四次即可。

代码如下:

#include<bits/stdc++.h>
using namespace std;
const int maxn=200005;
int n,m,k,hsh[5],S[maxn],T[maxn],ans[maxn][4];
bool pd[maxn][4];
inline int read(){
	char ch=getchar();
	while (ch!='A'&&ch!='C'&&ch!='G'&&ch!='T') ch=getchar();
	if (ch=='A') return 0;
	else if (ch=='C') return 1;
	else if (ch=='G') return 2;
	else return 3;
}
void prework(){
	int l=0,r=-1;
	for (int i=0;i<=n;i++){
		while (l<i-k) hsh[S[l]]--,l++;
		while (r<i+k&&r<n) r++,hsh[S[r]]++;
		for (int j=0;j<4;j++)
			if (hsh[j]) pd[i][j]=1; else pd[i][j]=0;
	}
}
namespace FFT{
	const int maxm=(1<<19)+5;
	const double Pi=acos(-1.0);
	int R[maxm],limn,p[maxm];
	struct comx{
		double x,y;
		comx(double xx=0,double yy=0) {x=xx,y=yy;}
		comx operator +(const comx b){return comx(x+b.x,y+b.y);}
		comx operator -(const comx b){return comx(x-b.x,y-b.y);}
		comx operator *(const comx b){return comx(x*b.x-y*b.y,x*b.y+y*b.x);}
	}a[maxm],b[maxm],w[maxm];
	void fft(comx *a,int lim){
		for (int i=0;i<lim;i++)
			if (R[i]>i) swap(a[i],a[R[i]]);
		for (int t=lim>>1,d=1;d<lim;d<<=1,t>>=1)
			for (int i=0;i<lim;i+=(d<<1))
				for (int j=0;j<d;j++){
					comx p=w[t*j]*a[i+j+d];
					a[i+j+d]=a[i+j]-p,a[i+j]=a[i+j]+p;
				}
	}
	void pre(int x){
		int L=0; limn=1;
		while (limn<=n+m) limn<<=1,L++;
		for (int i=0;i<limn;i++){
			a[i].x=a[i].y=b[i].x=b[i].y=0.0;
			R[i]=((R[i>>1]>>1)|((i&1)<<(L-1)));
			w[i]=comx(cos(2.0*Pi/limn*i),sin(2.0*Pi/limn*i));
		}
		for (int i=0;i<=n;i++) if (pd[i][x]==1) a[i].x=0; else a[i].x=1;
		for (int i=0;i<=m;i++) if (T[i]==x) b[m-i].x=1; else b[m-i].x=0;
	}
	void solve(int x){
		pre(x);
		fft(a,limn); fft(b,limn);
		for (int i=0;i<limn;i++) a[i]=a[i]*b[i],w[i].y=-w[i].y;
		fft(a,limn);
		for (int i=0;i<limn;i++) w[i].y=-w[i].y,a[i].x/=limn;
		memset(p,0,sizeof(p));
		for (int i=0;i<=n+m+1;i++) p[i]=(int)(a[i].x+0.5);
		for (int i=m;i<=n;i++) if (p[i]==0) ans[i][x]=0; else ans[i][x]=1;
	}
}
int main(){
	scanf("%d%d%d",&n,&m,&k);
	for (int i=0;i<n;i++) S[i]=read();
	for (int i=0;i<m;i++) T[i]=read();
	n--,m--;
	prework();
	for (int i=0;i<4;i++) FFT::solve(i);
	int sum=0;
	for (int i=m;i<=n;i++)
		if (ans[i][0]==0&&ans[i][1]==0&&ans[i][2]==0&&ans[i][3]==0) sum++;
	printf("%d\n",sum);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/DYT_B/article/details/85299906
今日推荐