#6250. 「CodePlus 2017 11 月赛」找爸爸
题目描述
小 A 最近一直在找自己的爸爸,用什么办法呢,就是 DNA 比对。
小 A 有一套自己的 DNA 序列比较方法,其最终目标是最大化两个 DNA 序列的相似程度,具体步骤如下:
- 给出两个 DNA 序列,第一个长度为 nnn,第二个长度为 mmm。
- 在两个序列的任意位置插入任意多的空格,使得两个字符串长度相同。
- 逐位进行匹配,如果两个序列相同位置上的字符都不是空格,假设第一个是 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 数组,具体顺序如下所示。
最后一行两个用空格隔开的正整数 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, -1000le 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}{ ext{A}, ext{T}, ext{G}, ext{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[5][5]; void work1(){ int ans=d[a[1]][b[1]]; ans=max(ans,-A); printf("%d",ans); } int main(){ scanf("%s%s",s1+1,s2+1); l1=strlen(s1+1);l2=strlen(s2+1); for(int i=1;i<=l1;i++){ if(s1[i]=='A')a[i]=1; if(s1[i]=='T')a[i]=2; if(s1[i]=='G')a[i]=3; if(s1[i]=='C')a[i]=4; } for(int i=1;i<=l2;i++){ if(s2[i]=='A')b[i]=1; if(s2[i]=='T')b[i]=2; if(s2[i]=='G')b[i]=3; if(s2[i]=='C')b[i]=4; } for(int i=1;i<=4;i++) for(int j=1;j<=4;j++) scanf("%d",&d[i][j]); scanf("%d%d",&A,&B); if(l1==l2&&l1==1){work1();return 0;} }
#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[5][5],f[maxn][maxn][2][2]; void work(){ memset(f,-0x3f,sizeof(f)); f[0][0][0][0]=0; for(int i=0;i<=n;i++){ for(int j=0;j<=m;j++){ if(i==j&&j==0)continue; if(i&&j){ f[i][j][0][0]=max(f[i][j][0][0],f[i-1][j-1][0][0]+d[a[i]][b[j]]); f[i][j][0][0]=max(f[i][j][0][0],f[i-1][j-1][0][1]+d[a[i]][b[j]]); f[i][j][0][0]=max(f[i][j][0][0],f[i-1][j-1][1][0]+d[a[i]][b[j]]); } if(i){ f[i][j][0][1]=max(f[i][j][0][1],f[i-1][j][0][1]-B); f[i][j][0][1]=max(f[i][j][0][1],f[i-1][j][0][0]-A); f[i][j][0][1]=max(f[i][j][0][1],f[i-1][j][1][0]-A); } if(j){ f[i][j][1][0]=max(f[i][j][1][0],f[i][j-1][1][0]-B); f[i][j][1][0]=max(f[i][j][1][0],f[i][j-1][0][0]-A); f[i][j][1][0]=max(f[i][j][1][0],f[i][j-1][0][1]-A); } } } } int main(){ scanf("%s%s",s1+1,s2+1); n=strlen(s1+1);m=strlen(s2+1); for(int i=1;i<=n;i++){ if(s1[i]=='A')a[i]=1; if(s1[i]=='T')a[i]=2; if(s1[i]=='G')a[i]=3; if(s1[i]=='C')a[i]=4; } for(int i=1;i<=m;i++){ if(s2[i]=='A')b[i]=1; if(s2[i]=='T')b[i]=2; if(s2[i]=='G')b[i]=3; if(s2[i]=='C')b[i]=4; } for(int i=1;i<=4;i++) for(int j=1;j<=4;j++) scanf("%d",&d[i][j]); scanf("%d%d",&A,&B); work(); int ans=max(f[n][m][0][0],max(f[n][m][1][0],f[n][m][0][1])); printf("%d",ans); return 0; }