【POJ No. 2778】DNA 序列 DNA Sequence

news2024/11/20 3:26:12

【POJ No. 2778】DNA 序列 DNA Sequence

北大OJ 题目地址

在这里插入图片描述

【题意】

DNA序列是一个只包含A、C、T和G的序列。分析DNA序列片段非常有用,若动物的DNA序列包含片段ATC,则意味着该动物可能患有遗传病。

给定m 个遗传病片段,求有多少种长度为n 的DNA序列不包含这些片段。

【输入输出】

输入:

第1行包含两个整数m (0≤m ≤10)和n (1≤n ≤2×109)。m 是遗传病片段的数量,n 是序列的长度。接下来的M 行,每行都包含一个DNA遗传病片段(长度不大于10)。

输出:

一个整数,不包含遗传病的DNA序列数mod 100000。

【样例】

在这里插入图片描述

【思路分析】

DNA序列只包含A、G、C、T共4种字母,给定m 个DNA遗传病片段,求有多少长度为n 的DNA序列不包含遗传病片段,可采用AC自动机解决。

【算法设计】

① 将遗传病片段插入字典树中。

② 构建AC自动机。注意:若当前节点的失败指针有结束标记,则对当前节点也要标记。

③ 构建邻接矩阵。对所有未标记的节点都重新编号,根据AC自动机构建邻接矩阵。

④ 求解矩阵的n 次幂,可用矩阵快速幂求解。

【举个栗子】

求解答案和矩阵有什么关系呢?

假设遗传病片段为{“ACG”, “C”},则将两个字符串插入字典树中并构建AC自动机。

从每个节点出发的边有4条(A、T、C、G)。

在这里插入图片描述

从状态0出发走1步有4种走法:①走A到状态1(安全);②走C到状态4(危险);③走T到状态0(安全);④走G到状态0(安全)。所以当n =1时,答案是3。

当n =2时,从状态0出发走2步,形成一个长度为2的字符串,只要在路径上没有经过危险节点,则有几种走法,答案就是几种。以此类推走n 步,就形成长度为n 的字符串。

这实际上相当于二元关系的复合运算,可以用图论里面的邻接矩阵相乘求解。

对上图的AC自动机建立邻接矩阵M :

2 1 0 0 1
2 1 1 0 0 
1 1 0 1 1
2 1 0 0 1
2 1 0 0 1

其中,M[i , j ]表示从节点i 到j 只走1步有几种走法,M 的n 次幂表示从节点i 到j 走n 步有几种走法。

注意:要去掉危险节点的行和列。节点3和4是遗传病片段的结尾,是危险节点,节点2的失败指针指向4,当匹配“AC”时也就匹配了“C”,所以2也是危险节点。去掉危险节点2、3、4后,邻接矩阵变成M :

2 1
2 1

计算M[][]的n 次幂,∑(M[0, i ]) mod 100000就是答案。由于n很大,所以使用矩阵快速幂计算矩阵的n 次幂。

【算法实现】

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>

using namespace std;

const int maxn=105;
const int K=4;
const int MOD=100000;

struct mat{
	int a[maxn][maxn];
	mat(){
		memset(a,0,sizeof(a));
	}
};
int root,L;

mat mul(mat A,mat B){//矩阵乘法
    mat C;
    for(int i=0;i<L;i++)
        for(int j=0;j<L;j++)
            for(int k=0;k<L;k++)
                C.a[i][j]=(C.a[i][j]+(long long)A.a[i][k]*B.a[k][j])%MOD;
    return C;
}

mat pow(mat A,int n){//A^n
    mat ans;
    for(int i=0;i<L;i++)
        ans.a[i][i]=1;//单位矩阵 
    while(n>0){
        if(n&1)
			ans=mul(ans,A);
        A=mul(A,A);
        n>>=1;
    }
    return ans;
}

struct ACAutomata{
    int next[maxn][K],fail[maxn],end[maxn],id[maxn];
	int idx(char ch){//转化数字
        switch(ch){
            case 'A':return 0;
            case 'C':return 1;
            case 'T':return 2;
            case 'G':return 3;
        }
        return -1;
    }
    int newNode(){//新建结点 
        for(int i=0;i<K;i++)
			next[L][i]=-1;
        end[L]=0;
        return L++;
    }
    void init(){//初始化
        L=0;
        root=newNode();
    }
    void insert(char s[]){//插入一个结点
        int len=strlen(s);
        int p=root;
        for (int i=0;i<len;i++){
            int ch=idx(s[i]);
            if(next[p][ch]==-1)
				next[p][ch]=newNode();
            p=next[p][ch];
        }
        end[p]++;
    }
    void build(){//构建AC自动机
        queue<int> Q;
        fail[root]=root;
        for(int i=0;i<K;i++){
            if(next[root][i]==-1){
                next[root][i]=root;
            }
			else{
                fail[next[root][i]]=root;
                Q.push(next[root][i]);
            }
        }
        while(Q.size()){
            int now=Q.front();
            Q.pop();
            if(end[fail[now]])
				end[now]++;//重要!!如果当前结点的失败指针end有结束标记,当前结点的end++ 
            for(int i=0;i<K;i++){
                if(next[now][i]!=-1){
                    fail[next[now][i]]=next[fail[now]][i];
                    Q.push(next[now][i]);
                }
				else
					next[now][i]=next[fail[now]][i];
            }
        }
    }

    int query(int n){
        mat F;
        int ids=0;
        memset(id,-1,sizeof(id));
        for(int i=0;i<L;i++)//对未标记的结点重新编号 
        	if(!end[i])
        		id[i]=ids++;
        for(int u=0;u<L;u++){
        	if(end[u]) continue;
        	for(int j=0;j<K;j++){
                int v=next[u][j];
                if(!end[v])
					F.a[id[u]][id[v]]++;
            }
		}
		L=ids;
	    F=pow(F,n);
	    int res=0;
	    for(int i=0;i<L;i++)
	    	res=(res+F.a[0][i])%MOD;
	    return res;
    }
}ac;

int main(){
	
    int m,n;
    char str[20];
    while(~scanf("%d%d",&m,&n)){
        ac.init();
        while (m--){
            scanf("%s",str);
            ac.insert(str);
        }
        ac.build();
        printf("%d\n",ac.query(n));
    }
	
    return 0;
}

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/77097.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

自动驾驶两大路线对决,渐进式玩家为何更容易得人心?

HiEV消息&#xff08;文/长海&#xff09;对自动驾驶赛道而言&#xff0c;2022年的冬天格外冷冽。寒潮袭来&#xff0c;从各家的应变方式看&#xff0c;不同路径的玩家呈现“冰火两重天”&#xff0c;进化的趋势也越来越清晰。 以Waymo为代表、持续研发L4级无人驾驶的跨越式路线…

web课程设计网页规划与设计 :DW旅游主题网页设计——凤阳智慧旅游官方-地方旅游网站模板html源码HTML+CSS+JavaScript

&#x1f468;‍&#x1f393;学生HTML静态网页基础水平制作&#x1f469;‍&#x1f393;&#xff0c;页面排版干净简洁。使用HTMLCSS页面布局设计,web大学生网页设计作业源码&#xff0c;这是一个不错的旅游网页制作&#xff0c;画面精明&#xff0c;排版整洁&#xff0c;内容…

ONES X 华西证券|以需求全流程管控,洞见金融数据价值

近日&#xff0c;ONES 签约全国一流证券金融服务商——华西证券&#xff0c;助推华西证券构建需求全流程管控体系&#xff0c;保障需求任务的上下游衔接与顺畅流转&#xff0c;做到系统内所有数据透明化、线上化、统一化&#xff0c;提高团队协同效率&#xff0c;打破「部门墙」…

所谓“生活的艺术“, 就是悠闲二字

关于作者 作为陈独秀、胡适、鲁迅的同时代人&#xff0c;林语堂是"五四"新文化运动的参与者&#xff0c;中国现 代著名作家、学者、翻译家、语言学家&#xff0c;新道家代表人物。他清晰地看到了关于中国 传统文化观点的两种极端倾向&#xff0c;一种是把 中国传统文…

R语言VAR模型的不同类型的脉冲响应分析

目录 模型与数据 估算值 预测误差脉冲响应 识别问题 正交脉冲响应 结构脉冲反应 广义脉冲响应 参考文献 最近我们被客户要求撰写关于脉冲响应分析的研究报告&#xff0c;包括一些图形和统计输出。脉冲响应分析是采用向量自回归模型的计量经济学分析中的重要一步。它们的…

火爆出圈的ChatGPT,你也来体验一下吧!

最近网络上流行了一个叫ChatGPT的东西&#xff0c;他到底是什么东西&#xff1f; ChatGPT是人工智能实验室OpenAI发布的一款对话式聊天机器人。他可以解答很多刁钻有难度的问题&#xff0c;一经发布就火遍科技圈。12月4日&#xff0c;马斯克在咨询该聊天机器人关于推特经营的建…

构建高性能内存队列:Disruptor 永远滴神~

我们清楚使用锁的性能比较低&#xff0c;尽量使用无锁设计。接下来就我们来认识下Disruptor。 Disruptor简单使用 先简单介绍下&#xff1a; Disruptor它是一个开源的并发框架&#xff0c;并获得2011 Duke’s程序框架创新奖【Oracle】&#xff0c;能够在无锁的情况下实现网络…

单机存储系统可靠性及相关技术介绍

一、存储系统可靠性的影响因素单机存储系统包括存储硬件和存储软件。存储硬件又包含存储介质、存储控制器、设备固件&#xff1b;存储软件栈层次则更为复杂&#xff0c;以Linux为例包括&#xff1a;存储设备驱动层、 块设备层(Block Layer)、可选的虚拟块设备层(Device Mapper)…

新手使用wvp-pro和zlm的菜鸟说明(手把手教)

对于wvp-pro的使用&#xff0c;很多大佬都是白嫖菜鸟党&#xff0c;很多都第一次使用wvp&#xff0c;甚至第一次接触国标&#xff0c;连国标最基本流程都不清楚。所以写此文档以供各位菜鸟大佬点评指正 看此文档前提&#xff1a; 第一&#xff1a;先看三遍zlm和wvp的wiki&…

【光照感知子场:差分感知融合模块与中间融合策略相结合】

PIAFusion: A progressive infrared and visible image fusion network based on illumination aware 本文提出了一种基于光照感知的渐进式图像融合网络PIAFusion&#xff0c;自适应地保持显著目标的亮度分布和背景的纹理信息。具体而言&#xff0c;我们设计了一个光照感知子网…

【Java基础篇】基础知识易错集锦(一)

在学习的路上&#xff0c;我们只记得学习新的知识&#xff0c;却忽略了一切新知识都是在旧知识的基础上&#xff1b;努力奔跑的过程中&#xff0c;也要记得常回头看看&#xff1b; 题目展示&#xff1a; 解析&#xff1a; abstract是抽象的意思&#xff0c;在java中&#xff0…

【Vue 快速入门】使用vue脚手架创建一个项目

文章目录一、环境检查1.安装node环境2.脚手架配置3.不同版本vue介绍二、创建项目三、脚手架配置解说1.配置解说2.我的第一个vue程序一、环境检查 1.安装node环境 Node.js发布于2009年5月&#xff0c;由Ryan Dahl开发&#xff0c;是一个基于Chrome V8引擎的JavaScript运行环境…

Flutter - AlignmentGeometry :Alignment 和 FractionalOffset

AlignmentGeometry 是一个抽象类&#xff0c;它有两个常用的子类&#xff1a;Alignment和 FractionalOffset Alignment Alignment继承自AlignmentGeometry&#xff0c;表示矩形内的一个点&#xff0c;他有两个属性x、y&#xff0c;分别表示在水平和垂直方向的偏移 上图中 Flu…

阳光保险港交所上市:年营收1200亿 市值超600亿港元

雷递网 雷建平 12月9日阳光保险集团股份有限公司 (简称&#xff1a;“阳光保险”&#xff0c;06963)今日在港交所上市&#xff0c;发行价为每股5.83港元&#xff0c;募资净额为64.195亿港元。若行使超额配股权&#xff0c;阳光保险可额外再募资9.81亿港元。阳光保险发行价为5.8…

软件测试 -- 进阶 7 软件测试环境构建 与 测试数据准备

工欲善其事&#xff0c;必先利其器。-- 《论语卫灵公》 释译&#xff1a;工匠想要工作做好&#xff0c;一定要先让工具锋利。比喻要做好一件事&#xff0c;准备工作非常重要。 1. 为什么要构建测试环境、准备测试数据 提前准备测试所需资源保证测试有效执行保证测试用序执…

ChatGPT新玩法来了,微信聊天机器人

前言 上一篇文章中说了ChatGPT是什么&#xff0c;然后怎么注册使用。 传送门&#xff1a;花了1块钱体验一把最近很火的ChatGPT 但是实际操作下来还是有不少小伙伴跟我一样遇到各种坑。 没有科学上网工具OpenAI的服务在你的国家无法使用&#xff08;最多的问题&#xff09; 注…

自动驾驶之夜间检测调研

1. ExDark 第一个 公开 特定的提供 natural low-light images for object的数据集 7363张 low-light images, 12 classes Low-light image enhancement: IVC database. general image enhancement而非特指low-light. 黑夜是人工合成的,可以找到原图像See-in-the-Dark datase…

如何创建Spring项目以及如何使用?

目录&#xff1a; 1.创建Spring项目 2.将对象存储在Spring中 3.从Spring中取出对象 4.使用对象 5.总结 Spring 就是⼀个包含了众多⼯具⽅法的 IoC 容器&#xff0c;它具备两个最基本的功能&#xff1a; 将对象存储到容器&#xff08;Spring&#xff09;中&#xff1b;从容器…

Web大学生网页作业成品——美食餐饮网站设计与实现(HTML+CSS+JavaScript)

&#x1f468;‍&#x1f393;静态网站的编写主要是用HTML DIVCSS JS等来完成页面的排版设计&#x1f469;‍&#x1f393;,常用的网页设计软件有Dreamweaver、EditPlus、HBuilderX、VScode 、Webstorm、Animate等等&#xff0c;用的最多的还是DW&#xff0c;当然不同软件写出的…

java SpringMVC 之 表现层与前端数据传输 SSM整合 异步处理前后台处理联调 拦截器

SSM整合 项目结构配置搭建 pom的依赖&#xff1a; <dependencies><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>3.8.1</version><scope>test</scope></dependency><de…