loj #6250. 「CodePlus 2017 11 月赛」找爸爸

时间:2022-08-20 09:29:56

#6250. 「CodePlus 2017 11 月赛」找爸爸

题目描述

小 A 最近一直在找自己的爸爸,用什么办法呢,就是 DNA 比对。

小 A 有一套自己的 DNA 序列比较方法,其最终目标是最大化两个 DNA 序列的相似程度,具体步骤如下:

  1. 给出两个 DNA 序列,第一个长度为 nnn,第二个长度为 mmm。
  2. 在两个序列的任意位置插入任意多的空格,使得两个字符串长度相同。
  3. 逐位进行匹配,如果两个序列相同位置上的字符都不是空格,假设第一个是 xxx,第二个是 yyy,那么他们的相似程度由 d(x,y)d(x,y)d(x,y) 定义。对于两个序列中任意一段极长的长度为 kkk的连续空格,我们定义这段空格的相似程度为 g(k)=−A−B(k−1)g(k)=-A-B(k-1)g(k)=−A−B(k−1)。

那么最终两个序列的相似程度就是所有的 d(x,y)d(x,y)d(x,y) 加上所有的极长空格段的相似程度之和。

现在小 A 通过某种奥妙重重的方式得到了小 B 的 DNA 序列中的一段,他想请你帮他算一下小 A 的 DNA 序列和小 B 的 DNA 序列的最大相似程度。

输入格式

输入第 111 行一个字符串,表示小 A 的 DNA 序列。

输入第 222 行一个字符串,表示小 B 的 DNA 序列。

接下来 444 行,每行 444 个整数,用空格隔开,表示 ddd 数组,具体顺序如下所示。

d(A,A)d(A,A)d(A,A) d(A,T)d(A,T)d(A,T) d(A,G)d(A,G)d(A,G) d(A,C)d(A,C)d(A,C)
d(T,A)d(T,A)d(T,A) d(T,T)d(T,T)d(T,T) d(T,G)d(T,G)d(T,G) d(T,C)d(T,C)d(T,C)
d(G,A)d(G,A)d(G,A) d(G,T)d(G,T)d(G,T) d(G,G)d(G,G)d(G,G) d(G,C)d(G,C)d(G,C)
d(C,A)d(C,A)d(C,A) d(C,T)d(C,T)d(C,T) d(C,G)d(C,G)d(C,G) d(C,C)d(C,C)d(C,C)

最后一行两个用空格隔开的正整数 A,BA,BA,B,意义如题中所述。

输出格式

输出共一行,表示两个序列的最大相似程度。

样例

样例输入

ATGG
ATCC
5 -4 -4 -4
-4 5 -4 -4
-4 -4 5 -4
-4 -4 -4 5
2 1

样例输出

4

样例解释

首先,将序列补成如下形式(- 代表空格)

ATGG--
AT--CC

然后所有 d(x,y)d(x,y)d(x,y) 的和为 d(A,A)+d(T,T)=10d(A,A)+d(T,T)=10d(A,A)+d(T,T)=10,所有极长连续空格段的相似程度之和为 g(2)+g(2)=−6g(2)+g(2)=-6g(2)+g(2)=−6。总和为 444,可以验证,这是相似程度最大的情况。

数据范围与提示

对于所有测试点,有 0<B<A≤1000,−1000≤d(x,y)≤1000,d(x,y)=d(y,x)0< B<A \le 1000, -1000\le d(x,y)\le 1000,d(x,y)=d(y,x)0<B<A≤1000,−1000≤d(x,y)≤1000,d(x,y)=d(y,x),序列只包含 {A,T,G,C}\{\text{A},\text{T},\text{G},\text{C}\}{A,T,G,C} 四种字符。

测试点编号 n+mn + mn+m 的范围 特殊约定
1 n=m=1n = m = 1n=m=1 无特殊要求
2 n+m≤15n + m \leq 15n+m≤15
3 n+m≤300n + m \leq 300n+m≤300
4
5 n+m≤3000n + m \leq 3000n+m≤3000 序列中只包含一种字符
6 无特殊要求
7
8
9
10

来自 CodePlus 2017 11 月赛,清华大学计算机科学与技术系学生算法与竞赛协会 荣誉出品。
Credit:idea/邢健开 命题/邢健开 验题/陈宇
Git Repo:https://git.thusaac.org/publish/CodePlus201711
感谢腾讯公司对此次比赛的支持。

#include<iostream>
#include<cstdio>
#include<cstring>
#define maxn 1010
using namespace std;
char s1[maxn],s2[maxn];
int l1,l2,A,B,a[maxn],b[maxn],d[][];
void work1(){
int ans=d[a[]][b[]];
ans=max(ans,-A);
printf("%d",ans);
}
int main(){
scanf("%s%s",s1+,s2+);
l1=strlen(s1+);l2=strlen(s2+);
for(int i=;i<=l1;i++){
if(s1[i]=='A')a[i]=;
if(s1[i]=='T')a[i]=;
if(s1[i]=='G')a[i]=;
if(s1[i]=='C')a[i]=;
}
for(int i=;i<=l2;i++){
if(s2[i]=='A')b[i]=;
if(s2[i]=='T')b[i]=;
if(s2[i]=='G')b[i]=;
if(s2[i]=='C')b[i]=;
}
for(int i=;i<=;i++)
for(int j=;j<=;j++)
scanf("%d",&d[i][j]);
scanf("%d%d",&A,&B);
if(l1==l2&&l1==){work1();return ;}
}

10分 手玩

#include<iostream>
#include<cstdio>
#include<cstring>
#define maxn 3010
using namespace std;
char s1[maxn],s2[maxn];
int n,m,A,B,a[maxn],b[maxn],d[][],f[maxn][maxn][][];
void work(){
memset(f,-0x3f,sizeof(f));
f[][][][]=;
for(int i=;i<=n;i++){
for(int j=;j<=m;j++){
if(i==j&&j==)continue;
if(i&&j){
f[i][j][][]=max(f[i][j][][],f[i-][j-][][]+d[a[i]][b[j]]);
f[i][j][][]=max(f[i][j][][],f[i-][j-][][]+d[a[i]][b[j]]);
f[i][j][][]=max(f[i][j][][],f[i-][j-][][]+d[a[i]][b[j]]);
}
if(i){
f[i][j][][]=max(f[i][j][][],f[i-][j][][]-B);
f[i][j][][]=max(f[i][j][][],f[i-][j][][]-A);
f[i][j][][]=max(f[i][j][][],f[i-][j][][]-A);
}
if(j){
f[i][j][][]=max(f[i][j][][],f[i][j-][][]-B);
f[i][j][][]=max(f[i][j][][],f[i][j-][][]-A);
f[i][j][][]=max(f[i][j][][],f[i][j-][][]-A);
}
}
}
}
int main(){
scanf("%s%s",s1+,s2+);
n=strlen(s1+);m=strlen(s2+);
for(int i=;i<=n;i++){
if(s1[i]=='A')a[i]=;
if(s1[i]=='T')a[i]=;
if(s1[i]=='G')a[i]=;
if(s1[i]=='C')a[i]=;
}
for(int i=;i<=m;i++){
if(s2[i]=='A')b[i]=;
if(s2[i]=='T')b[i]=;
if(s2[i]=='G')b[i]=;
if(s2[i]=='C')b[i]=;
}
for(int i=;i<=;i++)
for(int j=;j<=;j++)
scanf("%d",&d[i][j]);
scanf("%d%d",&A,&B);
work();
int ans=max(f[n][m][][],max(f[n][m][][],f[n][m][][]));
printf("%d",ans);
return ;
}

100分 动态规划