zoukankan      html  css  js  c++  java
  • 【codeforces 528D】 Fuzzy Search

    http://codeforces.com/problemset/problem/528/D (题目链接)

    题意

      给定母串和模式串,字符集大小为${4}$,给定${k}$,模式串在某个位置匹配当且仅当任意位置模式串的这个字符所对应的母串的位置的左右${k}$个字符之内有一个与它相同的,求匹配次数。

    Solution

      毛爷爷论文题。我们将${4}$种不同的字符分开计算贡献。每一次计算,先预处理出母串种的每个位置能否匹配,对于每个能够匹配的位置,我们将它赋为${1}$,不能匹配则赋为${0}$,将其存放在数组${A}$中。对于模式串,如果它这一位等于当前计算的这个字符,就将这一位赋为${1}$,否则赋为${0}$,将其存放在数组${B}$中。这样的话,我们将模式串倒过来,那么最后对于这个字符来说,模式串位于某一位置与主串的匹配字符数量就是${A}$和${B}$的卷积。那么最后将所有${4}$种字符的贡献算完,如果某一位置的卷积等于模式串长度,那么久意味着模式串处于这一位置的时候可以与主串匹配。于是我们就可以用${FFT}$来解决这个问题了。

    细节

      ${FFT}$最后统计的时候要转成${LL}$而不是${int}$。

    代码

    // codeforces 528D
    #include<algorithm>
    #include<iostream>
    #include<cstdlib>
    #include<complex>
    #include<cstring>
    #include<cstdio>
    #include<cmath>
    #define LL long long
    #define inf 2147483640
    #define Pi acos(-1.0)
    #define free(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout);
    using namespace std;
    
    typedef complex<double> E;
    const int maxn=800010;
    int n,m,N,M,K,L;
    int ans[maxn],rev[maxn],id[maxn],cnt[5],vis[maxn][5];
    char a[maxn],b[maxn];
    E A[maxn],B[maxn];
    
    void FFT(E *a,int f) {
    	for (int i=0;i<N;i++) if (rev[i]>i) swap(a[i],a[rev[i]]);
    	for (int i=1;i<N;i<<=1) {
    		E wn(cos(Pi/i),sin(Pi/i));
    		for (int p=i<<1,j=0;j<N;j+=p) {
    			E w(1,0);
    			for (int k=0;k<i;k++,w*=wn) {
    				E x=a[k+j],y=w*a[k+j+i];
    				a[k+j]=x+y;a[k+j+i]=x-y;
    			}
    		}
    	}
    	if (f==-1) reverse(a+1,a+N);
    }
    int main() {
    	scanf("%d%d%d",&n,&m,&K);
    	scanf("%s%s",a+1,b+1);
    	id['A']=1;id['T']=2;id['G']=3;id['C']=4;
    	for (int l=0,r=0,i=1;i<=n;i++) {   //get了一个比较美观的写法
    		while (l<n && l<i-K) cnt[id[(int)a[l++]]]--;
    		while (r<n && r<i+K) cnt[id[(int)a[++r]]]++;
    		for (int j=1;j<=4;j++) if (cnt[j]) vis[i][j]=1;
    	}
    	M=n+m;
    	for (N=1;N<=M;N<<=1) L++;
    	for (int i=0;i<N;i++) rev[i]=(rev[i>>1]>>1) | ((i&1)<<(L-1));
    	for (int k=1;k<=4;k++) {
    		memset(A,0,sizeof(A));
    		memset(B,0,sizeof(B));
    		for (int i=1;i<=n;i++) {
    			if (vis[i][k]) A[i-1]=1;
    			else A[i-1]=0;
    		}
    		for (int i=1;i<=m;i++) {
    			if (id[(int)b[i]]==k) B[m-i]=1;
    			else B[m-i]=0;
    		}
    		FFT(A,1);FFT(B,1);
    		for (int i=0;i<N;i++) A[i]*=B[i];
    		FFT(A,-1);
    		for (int i=0;i<N;i++) ans[i]+=(LL)(A[i].real()+0.5)/N;   //此处LL
    	}
    	int res=0;
    	for (int i=0;i<N;i++) if (ans[i]==m) res++;
    	printf("%d",res);
    	return 0;
    }
    
  • 相关阅读:
    关于下下载typora的相关说明
    Vue项目vscode 安装eslint插件的方法(代码自动修复)
    [0].Net开发者社区--您好大的官威啊!
    关于hadoop安装后无法访问web界面查看查看 NameNode 和 Datanode 信息
    C#(winform)记录阻止关闭页面方法
    Android开发:记录Cannot resolve symbol'R'问题解决记录
    C#Winform开发杂项记录
    C#Winform 使用NPOI导入、导出Excel
    C#记录一些用到的比对方法
    C#(Winform开发)Excel导出
  • 原文地址:https://www.cnblogs.com/MashiroSky/p/6344857.html
Copyright © 2011-2022 走看看