• [TJOI2017]DNA


    Description:

    加里敦大学的生物研究所,发现了决定人喜不喜欢吃藕的基因序列S,有这个序列的碱基序列就会表现出喜欢吃藕的性状,但是研究人员发现对碱基序列S,任意修改其中不超过3个碱基,依然能够表现出吃藕的性状。现在研究人员想知道这个基因在DNA链S0上的位置。所以你需要统计在一个表现出吃藕性状的人的DNA序列S0上,有多少个连续子串可能是该基因,即有多少个S0的连续子串修改小于等于三个字母能够变成S。

    Hint:

    (n le 10^5)

    Solution:

    由于字符集较小
    考虑分别计算每个字母的不匹配数量,再累加起来
    枚举四个字母,把原串的为该字母的位置赋为1,其他赋为0,匹配串反之
    这样就能不重不漏的统计出不匹配位置的数量
    统计后直接输出<=3的位置

    #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=4e5+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) a[i]=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()
    {
        int T;
        cin>>T;
        while(T--) {
        memset(cnt,0,sizeof(cnt)); ans=0;
        scanf("%s %s",s,t); n=strlen(s),m=strlen(t);
        for(int i=0;i<4;++i) solve("ACTG"[i]);
        for(int i=m-1;i<n;++i) ans+=cnt[i]<=3;
        printf("%d
    ",ans);
        }
        return 0;
    }
    
    
  • 相关阅读:
    msfvenom生成不同类型shell
    (CVE-2021-21972) VM vCenter任意文件上传漏洞复现
    linux新建普通账户并添加密码
    Linux监控平台、安装zabbix、修改zabbix的admin密码
    LVS DR模式搭建、keepalived+lvs
    负载均衡集群相关、LVS介绍、LVS调度算法、LVS NAT模式搭建
    集群相关、用keepalived配置高可用集群
    MySQL主从、环境搭建、主从配制
    Tomcat配置虚拟主机、tomcat的日志
    Tomcat介绍、安装jdk、安装Tomcat、配置Tomcat监听80端口
  • 原文地址:https://www.cnblogs.com/list1/p/10504712.html
Copyright © 2020-2023  润新知