题目描述
小 A 最近一直在找自己的爸爸,用什么办法呢,就是 DNA 比对。
小 A 有一套自己的 DNA 序列比较方法,其最终目标是最大化两个 DNA 序列的相似程度,具体步骤如下:
1. 给出两个 DNA 序列,第一个长度为
n
,第二个长度为
2. 在两个序列的任意位置插入任意多的空格,使得两个字符串长度相同。
3. 逐位进行匹配,如果两个序列相同位置上的字符都不是空格,假设第一个是
x
,第二个是
那么最终两个序列的相似程度就是所有的
d(x,y)
加上所有的极长空格段的相似程度之和。
现在小 A 通过某种奥妙重重的方式得到了小 B 的 DNA 序列中的一段,他想请你帮他算一下小 A 的 DNA 序列和小 B 的 DNA 序列的最大相似程度。
输入格式
输入第
1
一个字符串,表示小 A 的 DNA 序列。
输入第
接下来
4
行,每行
d(T,A)
d(T,T)
d(T,G)
d(T,C)
d(G,A)
d(G,T)
d(G,G)
d(G,C)
d(C,A)
d(C,T)
d(C,G)
d(C,C)
最后一行两个用空格隔开的正整数
A,B
,意义如题中所述。
输出格式
输出共一行,表示两个序列的最大相似程度。
样例输入
ATGG
ATCC
5 -4 -4 -4
-4 5 -4 -4
-4 -4 5 -4
-4 -4 -4 5
2 1
样例输出
4
样例解释
首先,将序列补成如下形式(-代表空格)
A T G G - -
A T - - C C
然后所有
d(x,y)
的和为
d(A,A)+d(T,T)=10
,所有极长连续空格段的相似程度之和为
g(2)+g(2)=−6
。总和为
4
,可以验证,这是相似程度最大的情况。
数据范围与提示
对于所有测试点,有
测试点编号 | n+m 的范围 | 特殊约定 |
---|---|---|
1 | n=m=1 | 无特殊要求 |
2 | n+m≤15 | 无特殊要求 |
3 | n+m≤300 | 无特殊要求 |
4 | n+m≤300 | 无特殊要求 |
5 | n+m≤3000 | 序列中只包含一种字符 |
6 | n+m≤3000 | 无特殊要求 |
7 | n+m≤3000 | 无特殊要求 |
8 | n+m≤3000 | 无特殊要求 |
9 | n+m≤3000 | 无特殊要求 |
10 | n+m≤3000 | 无特殊要求 |
来自 CodePlus 2017 11 月赛,清华大学计算机科学与技术系学生算法与竞赛协会 荣誉出品。
Credit:idea/邢健开 命题/邢健开 验题/陈宇
Git Repo:https://git.thusaac.org/publish/CodePlus201711
感谢腾讯公司对此次比赛的支持。
思路
直接dp,方程太长,看代码好了。
代码
#include <cstdio>
#include <algorithm>
#include <cstring>
const int maxn=3000;
const int inf=1000000000;
int f[maxn+10][maxn+10][2][2];
//f[i][j][k][l]代表A序列匹配到了i位,B序列匹配到了j位,k代表A序列末尾是否有空格,l代表B序列是否有空格
char s[maxn+10],t[maxn+10];
int a[maxn+10],b[maxn+10],w[4][4],lena,lenb,x,y;
int main()
{
scanf("%s%s",s+1,t+1);
lena=strlen(s+1);
lenb=strlen(t+1);
for(register int i=1; i<=lena; ++i)
{
if(s[i]=='A')
{
a[i]=0;
}
else if(s[i]=='T')
{
a[i]=1;
}
else if(s[i]=='G')
{
a[i]=2;
}
else if(s[i]=='C')
{
a[i]=3;
}
}
for(register int i=1; i<=lenb; ++i)
{
if(t[i]=='A')
{
b[i]=0;
}
else if(t[i]=='T')
{
b[i]=1;
}
else if(t[i]=='G')
{
b[i]=2;
}
else if(t[i]=='C')
{
b[i]=3;
}
}
for(register int i=0; i<4; ++i)
{
for(register int j=0; j<4; ++j)
{
scanf("%d",&w[i][j]);
}
}
scanf("%d%d",&x,&y);
f[0][0][0][0]=0;
f[0][0][0][1]=-inf;
f[0][0][1][0]=-inf;
for(register int i=1; i<=lena; ++i)
{
f[i][0][0][1]=-x-y*(i-1);
f[i][0][1][0]=f[i][0][0][0]=-inf;
}
for(register int i=1; i<=lenb; ++i)
{
f[0][i][1][0]=-x-y*(i-1);
f[0][i][0][1]=f[0][i][0][0]=-inf;
}
//上面赋初值,下面dp
for(register int i=1; i<=lena; ++i)
{
for(register int j=1; j<=lenb; ++j)
{
f[i][j][0][0]=std::max(f[i-1][j-1][0][0],std::max(f[i-1][j-1][0][1],f[i-1][j-1][1][0]))+w[a[i]][b[j]];
f[i][j][0][1]=std::max(f[i-1][j][0][0]-x,std::max(f[i-1][j][1][0]-x,f[i-1][j][0][1]-y));
f[i][j][1][0]=std::max(f[i][j-1][0][0]-x,std::max(f[i][j-1][0][1]-x,f[i][j-1][1][0]-y));
}
}
printf("%d\n",std::max(f[lena][lenb][0][0],std::max(f[lena][lenb][1][0],f[lena][lenb][0][1])));
return 0;
}