列表

详情


NC19875. [AHOI2006]基因匹配MATCH

描述

基因匹配(match) 卡卡昨天晚上做梦梦见他和可可来到了另外一个星球,这个星球上生物的DNA序列由无数种碱基排列而成(地球上只有4种),而更奇怪的是,组成DNA序列的每一种碱基在该序列中正好出现5次!这样如果一个DNA序列有N种不同的碱基构成,那么它的长度一定是5N。
卡卡醒来后向可可叙述了这个奇怪的梦,而可可这些日子正在研究生物信息学中的基因匹配问题,于是他决定为这个奇怪星球上的生物写一个简单的DNA匹配程序。 为了描述基因匹配的原理,我们需要先定义子序列的概念:若从一个DNA序列(字符串)s中任意抽取一些碱基(字符),将它们仍按在s中的顺序排列成一个新串u,则称u是s的一个子序列。对于两个DNA序列s1和s2,如果存在一个序列u同时成为s1和s2的子序列,则称u是s1和s2的公共子序列。 
卡卡已知两个DNA序列s1和s2,求s1和s2的最大匹配就是指s1和s2最长公共子序列的长度。
[任务] 编写一个程序:
从输入文件中读入两个等长的DNA序列;
计算它们的最大匹配;
向输出文件打印你得到的结果。

输入描述

输入文件中第一行有一个整数N,表示这个星球上某种生物使用了N种不同的碱基,以后将它们编号为1…N的整数。
以下还有两行,每行描述一个DNA序列:包含5N个1…N的整数,且每一个整数在对应的序列中正好出现5次。

输出描述

输出文件中只有一个整数,即两个DNA序列的最大匹配数目。

示例1

输入:

2
1 1 2 2 1 1 2 1 2 2
1 2 2 2 1 1 2 2 1 1

输出:

7

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++11(clang++ 3.9) 解法, 执行用时: 123ms, 内存消耗: 5092K, 提交时间: 2020-04-02 20:07:42

#include<bits/stdc++.h>
using namespace std;
int c[100020];
int a[100020];
int haha[100020];
vector<int>pos[100020];
int n,m;
void add(int x,int y)
{
	for(int i=x;i<=n;i+=i&-i)
	{
		c[i]=max(c[i],y);
	}
}
int ask(int x)
{
	int re=0;
	for(int i=x;i>0;i-=i&-i)
	{
		re=max(re,c[i]);
	}
	return re;
}
int main()
{
	cin>>n;
	n*=5;
	for(int i=1;i<=n;i++)
	{
		cin>>a[i];
	}
	for(int i=1;i<=n;i++)
	{
		cin>>haha[i];
		pos[haha[i]].push_back(i);
	}
	for(int i=1;i<=n;i++)
	{
		for(int j=4;j>=0;j--)
		{
			add(pos[a[i]][j],ask(pos[a[i]][j]-1)+1);
		}
	}
	cout<<ask(n)<<endl;
}

C++14(g++5.4) 解法, 执行用时: 139ms, 内存消耗: 4984K, 提交时间: 2019-09-29 09:48:58

#include <bits/stdc++.h>
using namespace std;
int c[100020];
int a[100020];
int haha[100020];
vector<int>pos[100020];
int n,m;
void add(int x,int y){
	for(int i=x;i<=n;i+=i&-i){
		c[i]=max(c[i],y);
	}
}
int ask(int x){
	int re=0;
	for(int i=x;i>0;i-=i&-i){
		re=max(re,c[i]);
	}
	return re;
}
int main(){
	cin>>n;
	n*=5;
	for(int i=1;i<=n;i++){
		cin>>a[i];
	}
	for(int i=1;i<=n;i++){
		cin>>haha[i];
		pos[haha[i]].push_back(i);
	}
	for(int i=1;i<=n;i++){
		for(int j=4;j>=0;j--){
			add(pos[a[i]][j],ask(pos[a[i]][j]-1)+1);
		}
	}
	cout<<ask(n)<<endl;
}

上一题