[SMOJ1810]基因测试
来源:互联网 发布:中央数据交换平台 编辑:程序博客网 时间:2024/06/05 17:50
题目描述
现代的生物基因测试已经很流行了。现在要测试色盲的基因组。有
N 个色盲的人和N 个非色盲的人参与测试。
基因组包含M 位基因,编号 1 至M 。每一位基因都可以用一个字符来表示,这个字符是‘A’、’C’、’G’、’T’四个字符之一。
例如:N=3,M=8 。色盲者1的8位基因组是: AATCCCAT
色盲者2的8位基因组是: ACTTGCAA
色盲者3的8位基因组是: GGTCGCAA
正常者1的8位基因组是: ACTCCCAG
正常者2的8位基因组是: ACTCGCAT
正常者3的8位基因组是: ACTTCCAT通过认真观察研究,生物学家发现,有时候可能通过特定的连续几位基因,就能区分开是正常者还是色盲者。
例如上面的例子,不需要8位基因,只需要看其中连续的4位基因就可以判定是正常者还是色盲者,这4位基因编号分别是:
(第2、3、4、5)。也就是说,只需要看第2,3,4,5这四位连续的基因,就能判定该人是正常者还是色盲者。
比如:第2,3,4,5这四位基因如果是GTCG,那么该人一定是色盲者。生物学家希望用最少的连续若干位基因就可以区别出正常者和色盲者,输出满足要求的连续基因的最少位数。
输入格式 1810.in
第一行,两个整数:
N 和M 。1≤N≤500 ,3≤M≤500 。
接下来有N 行,每一行是一个长度为M 的字符串,第i 行表示第i 位色盲者的基因组。
接下来又有N 行,每一行是一个长度为M 的字符串,第i 行表示第i 位正常者的基因组。
输出格式 1810.out
一个整数。
输入样例 1810.in
3 8
AATCCCAT
ACTTGCAA
GGTCGCAA
ACTCCCAG
ACTCGCAT
ACTTCCAT
输出样例 1810.out
4
题意:给定
上面这个概括可能会比较抽象,用样例来说明:
AATCCCAT
ACTTGCAA
GGTCGCAA
ACTCCCAG
ACTCGCAT
ACTTCCAT
对于所有长度为 1、2、3 的子串,无论从哪里开始,两部分中都有相等的子串。而如果子串长度为 4 呢?
从第 1 位开始的话,各个串的子串分别为 AATC、ACTT、GGTC(第一部分)、ACTC、ACTC 和 ACTT(第二部分)。可以看到,第一部分和第二部分中都出现了 ACTT,因此不能作为答案。
而如果从第 2 位开始,则可以发现各个串的子串分别为 ATCC、CTTG、GTCG(第一部分)、CTCC、CTCG 和 CTTC,在第一部分和第二部分中没有出现任何相等子串,因此答案就是 4。
首先明确一点,答案显然具有单调性。对于一个子串长度
那么我们的问题就是,对于一个给定的子串长度
既然只要从某一位开始的长度为
我们可以枚举第一部分中的每个子串,再枚举第二部分中的,一一匹配检查,但这样就有
这也就意味着我们至少要降一维的复杂度,那么最好入手的就是把一个嵌套改为两个并列。
事实上,用之前“不同子串个数”一题的字符串 hash 法,可以通过预处理,很好地在
这样一来,就可以在
参考代码:
#include <algorithm>#include <cstdio>#include <cstdlib>#include <cstring>#include <iostream>using namespace std;typedef unsigned long long ull;const int maxn = 1010;const int maxm = 510;const int prime = 30000007;int n, m;int str[maxn][maxm];ull p[maxn];ull sum[maxn][maxm];bool hash[prime];bool check(int x) { for (int i = 1; i + x != m + 2; ++i) { //起始位 bool bo = true; for (int j = 0; j != n; ++j) hash[(sum[j][i + x - 1] - sum[j][i - 1] * p[x] + prime) % prime] = true; //标记色盲 for (int j = n; j != (n << 1); ++j) if (hash[(sum[j][i + x - 1] - sum[j][i - 1] * p[x] + prime) % prime]) { bo = false; break; } //检查非色盲 for (int j = 0; j != n; ++j) hash[(sum[j][i + x - 1] - sum[j][i - 1] * p[x] + prime) % prime] = false; //清空 if (bo) return true; } return false;}int main(void) { freopen("1810.in", "r", stdin); freopen("1810.out", "w", stdout); scanf("%d%d", &n, &m); getchar(); p[0] = 1; for (int i = 1; i != m + 1; ++i) p[i] = (p[i - 1] << 2) % prime; //权的预处理 for (int i = 0; i != (n << 1); ++i) { for (int j = 1; j != m + 1; ++j) { char c; c = getchar(); //常数优化。。。 if (c == 'A') str[i][j] = 0; //重编码为 4 进制方便 hash else if (c == 'C') str[i][j] = 1; else if (c == 'G') str[i][j] = 2; else str[i][j] = 3; sum[i][j] = (((sum[i][j - 1] << 2) % prime) + str[i][j]) % prime; } getchar(); } int l = 1, r = m; while (l + 1 != r) { int mid = l + r >> 1; if (check(mid)) r = mid; else l = mid; } if (check(l)) printf("%d\n", l); else printf("%d\n", r); return 0;}
- [SMOJ1810]基因测试
- 软件测试的基因是什么?
- 基因
- 你的软件测试基因是什么?
- 软件测试企业的质量基因是什么?
- 基因数据处理9之BWA小数据集测试(成功)
- 基因预测
- 企业家基因
- 山寨基因
- 职业基因
- 基因检测
- 基因牛
- 基因 (BFS)
- 印记基因
- 基因牛
- 基因牛
- 基因牛
- 相似基因
- Python基础入门(十二)- dict 字典
- 输入某二叉树的前序遍历和中序遍历的结果重建出该二叉树。设输入的前序遍历和中序遍历的结果中都不含重复的数字。如输前序{1,2,4,7,3,5,6,8}和中序{4,7,2,1,5,3,8,6},则重建。
- 进制转换--数字转26字母进制-matlab
- 【机器学习(李宏毅)】 三、Bias and Variance
- maven+springMVC+mybatis+junit详细搭建过程
- [SMOJ1810]基因测试
- jenkins安装部署过程简记
- CentOS 7.2 安装 python 读 mysql
- C++核心知识整理——标准库和oop
- [高德地图 应用找不到本地方法nativeNewInstance] 代码正常,啥都没做就报错,地图当然也不能显示
- Intellij idea破解办法
- 正则表达式基本语法
- 关于欧拉函数和费马小定理的应用
- 【idea】基于jmeter的性能测试自动化平台开发