Description
基因匹配(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序列; 计算它们的最大匹配; 向输出文件打印你得到的结果。
Input
输入文件中第一行有一个整数N,表示这个星球上某种生物使用了N种不同的碱基,以后将它们编号为1…N的整数。 以下还有两行,每行描述一个DNA序列:包含5N个1…N的整数,且每一个整数在对应的序列中正好出现5次。
Output
输出文件中只有一个整数,即两个DNA序列的最大匹配数目。
Sample Input
2
1 1 2 2 1 1 2 1 2 2
1 2 2 2 1 1 2 2 1 1
Sample Output
7
HINT
[数据约束和评分方法]
60%的测试数据中:1<=N <= 1 000
100%的测试数据中:1<=N <= 20 000
这道题其实很麻烦
首先
读题是十分简单的
毕竟 只需要找两个数列的最长公共子序列
然而
数据真的好大 好大
我有点傻
不妨把lcs转成Lis吧
把第一个 数列的每个数的位置直接 带到下一个数上
这样就可以咯
但是
又要怎么转移呢、
有这样两种方式
如果每个数值只有一次
那就可以用相对万能的桶排
a[n]就表示n存在的位置
但是如果多了 就不好办了
如果出现的比较少
可以用几个桶
但是比较多了
就要换一种方法了
CRH大神的方法
循环 循环 用循环把两个数的位置处理
在我看来 这是玄学
烧脑程度过高
而且这是告诉你多少次的
奥不然该循环多少吃呢
不知道
my idea
不妨开数据结构吗
多生动啊
每个DNA中一个名字
一个数组
一个tmp 用来存次数
这样就可以咯
最后用第二个数列 循环解决就好了
最后把代码给大家
bling bling~~~
#include <stdio.h>
#include <algorithm>
using namespace std;
int ans2[2600001];
int dp[2600001];
int ans[2600001];
int l1=1;
struct DNA
{
int name;
int tmp;
int a[6];
};
DNA f[100001];
int find(int x)
{
int l=1;
int r=l1+1;
while(l<r)
{
int mid;
mid=l+r;
mid/=2;
if(dp[mid]<x)
l=mid+1;
else
r=mid;
}
return l;
}
int main()
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
f[i].name=i;
}
int q=1;
int t=1;
for(int i=1;i<=5*n;i++)
{
int k;
scanf("%d",&k);
f[k].tmp++;
f[k].a[f[k].tmp]=q;
q++;
ans[t]=k;
t+=5;
}
t=1;
for(int i=1;i<=25*n;i+=5)
{
scanf("%d",&ans2[t]);
t+=5;
}
for(int i=1;i<=25*n;i+=5)
{
int w=i;
ans2[i+1]=f[ans2[w]].a[4];
ans2[i+2]=f[ans2[w]].a[3];
ans2[i+3]=f[ans2[w]].a[2];
ans2[i+4]=f[ans2[w]].a[1];
ans2[i]=f[ans2[w]].a[5];
}
dp[1]=ans2[1];
for(int i=2;i<=25*n;i++)
{
if(dp[l1]<ans2[i])
{
l1++;
dp[l1]=ans2[i];
}
else
{
int k=find(ans2[i]);
dp[k]=ans2[i];
}
}
printf("%d",l1);
return 0;
}