• [CF528D]Fuzzy Seach


    Description:

    有两个基因串S和T,他们只包含AGCT四种字符。现在你要找出T在S中出现了几次。 有一个门限值k≥0。T在S的第i(1≤i≤|S|-|T|+1)个位置中出现的条件如下:把T的开头和S的第i个字符对齐,然后T中的每一个字符能够在S中找到一样的,且位置偏差不超过k的,那么就认为T在S的第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中出现的次数

    Hint:

    (n le 2*10^5)

    Solution:

    其实k就相当于左右k格都能匹配到这个字符
    故由于只有4种字符,我们可以单个考虑
    每次O(n)把该字符的位置处理好
    再累加看看是否cnt==m即可

    #include <map>
    #include <set>
    #include <stack>
    #include <cmath>
    #include <queue>
    #include <cstdio>
    #include <cstring>
    #include <cstdlib>
    #include <iostream>
    #include <algorithm>
    #define ls p<<1 
    #define rs p<<1|1
    using namespace std;
    typedef long long ll;
    const int mxn=1e6+5,inf=1e9;
    const double PI=acos(-1);
    int n,m,k,lim=1,ans,l,r[mxn],cnt[mxn];
    char s[mxn],t[mxn];
    
    inline int read() {
    	char c=getchar(); int x=0,f=1;
    	while(c>'9'||c<'0') {if(c=='-') f=-1;c=getchar();}
    	while(c<='9'&&c>='0') {x=(x<<3)+(x<<1)+(c&15);c=getchar();}
    	return x*f;
    }
    inline int chkmax(int &x,int y) {if(x<y) x=y;}
    inline int chkmin(int &x,int y) {if(x>y) x=y;}
    
    struct cp {
    	double x,y;
    	cp (double xx=0,double yy=0) {x=xx,y=yy;}
    	friend cp operator + (cp a,cp b) {
    		return cp(a.x+b.x,a.y+b.y);
    	}
    	friend cp operator - (cp a,cp b) {
    		return cp(a.x-b.x,a.y-b.y);
    	}
    	friend cp operator * (cp a,cp b) {
    		return cp(a.x*b.x-a.y*b.y,a.x*b.y+a.y*b.x);
    	}
    }a[mxn],b[mxn];
    
    void FFT(cp *p,int opt) 
    {
    	for(int i=0;i<lim;++i)
    		if(i<r[i]) swap(p[i],p[r[i]]);
    	for(int mid=1;mid<lim;mid<<=1) {
    		cp wn=cp(cos(PI/mid),opt*sin(PI/mid));
    		for(int len=mid<<1,j=0;j<lim;j+=len) {
    			cp w(1,0);
    			for(int k=0;k<mid;++k,w=w*wn) {
    				cp x=p[j+k],y=w*p[j+mid+k];
    				p[j+k]=x+y,p[j+mid+k]=x-y;
    			}
    		}
    	}	
    }
    
    void solve(char c) {
    	memset(a,0,sizeof(a)); memset(b,0,sizeof(b));
    	for(int i=0,las=-inf;i<n;++i) {
    		if(s[i]==c) las=i;
    		if(i-las<=k) a[i].x=1;
    	}
    	for(int i=n-1,las=inf;i>=0;--i) {
    		if(s[i]==c) las=i;
    		if(las-i<=k) a[i].x=1;
    	}
    	for(int i=0;i<m;++i) b[i].x=t[m-i-1]==c;
    	lim=1,l=0;
    	while(lim<=n+m-2) lim<<=1,++l;
    	for(int i=0;i<lim;++i)
    		r[i]=(r[i>>1]>>1)|((i&1)<<(l-1));
    	FFT(a,1); FFT(b,1); 
    	for(int i=0;i<=lim;++i) a[i]=a[i]*b[i];
    	FFT(a,-1);
    	for(int i=0;i<lim;++i) cnt[i]+=(int )(a[i].x/lim+0.5);
    }
    
    int main()
    {
    	n=read(); m=read(); k=read();
    	scanf("%s %s",s,t);
    	for(int i=0;i<4;++i) solve("ACTG"[i]);
    	for(int i=0;i<n+m;++i) ans+=cnt[i]==m;
    	printf("%d",ans);
        return 0;
    }
    
    
  • 相关阅读:
    Java 引用传递和值传递
    jenkins 自动化部署 spring boot 项目(多图)
    Mybatis学习笔记,持续更新
    ubuntu 安装并远程连接redis
    ubuntu redis 集群安装,超简单多图细腻操作
    ubuntu16.04 的 使用笔记
    阿里云 ubuntu16.04 下 ftp 的快速应用(包罗疑难问题解决方案)
    k8s的#容器镜像
    kubectl命令出现【The connection to the server localhost:8080 was refused
    CIDR无类别域间路由
  • 原文地址:https://www.cnblogs.com/list1/p/10504734.html
Copyright © 2020-2023  润新知