Luogu P4059 找爸爸
找爸爸
题目描述#
小A最近一直在找自己的爸爸,用什么办法呢,就是DNA比对。
小A有一套自己的DNA序列比较方法,其最终目标是最大化两个DNA序列的相似程度,具体步骤如下:
-
给出两个DNA序列,第一个长度为,第二个长度为。
-
在两个序列的任意位置插入任意多的空格,使得两个字符串长度相同
-
逐位进行匹配,如果两个序列相同位置上的字符都不是空格,假设第一个是,第二个是,那么他们的相似程度由定义。对于两个序列中任意一段极长的长度为的连续空格,我们定义这段空格的相似程度为。
那么最终两个序列的相似程度就是所有的加上所有的极长空格段的相似程度之和。
现在小A通过某种奥妙重重的方式得到了小B的DNA序列中的一段,他想请你帮他算一下小A的DNA序列和小B的DNA序列的最大相似程度。
输入格式#
输入第行一个字符串,表示小A的DNA序列。
输入第行一个字符串,表示小B的DNA序列。
接下来行,每行个整数,用空格隔开,表示数组,具体顺序如下所示。
d(A,A) d(A,T) d(A,G) d(A,C)
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)
最后一行两个用空格隔开的正整数,意义如题中所述。
输出格式#
输出共一行,表示两个序列的最大相似程度。
样例 #1#
样例输入 #1#
ATGG
ATCC
5 -4 -4 -4
-4 5 -4 -4
-4 -4 5 -4
-4 -4 -4 5
2 1
样例输出 #1#
4
提示#
样例解释#
首先,将序列补成如下形式("-"代表空格)
ATGG--
AT--CC
然后所有的和为
所有极长连续空格段的相似程度之和为
总和为,可以验证,这是相似程度最大的情况。
对于所有测试点,有,序列只包含四种字符。
SOLUTION#
首先我们考虑每个位置上的字符:
- 如果两个都为字符,那么它的贡献是给定的一个值
- 如果一个是空格一个是字符,那么他的贡献需要考虑他是的前一个是否也是空格
- 如果是第一个空格,则贡献为
- 如果不是第一个空格,则贡献为
- 如果连个都为空格,那么他的贡献不会增加,因此我们舍弃这种情况。
因此我们对于某个位置,只需要记录它的前一个位置的情况即可。
可以定义 分别表示 使用了 个字符 使用了 个字符 并且最后一对字符为:
- 0 均为字符
- 1 为空格,为字符
- 2 为空格,为字符
然后进行状态转移即可
CODE#
#include <bits/stdc++.h>
using namespace std;
#define rep(i, b, s) for(int i = (b); i <= (s); ++ i)
#define dec(i, b, s) for(int i = (b); i >= (s); -- i)
#define YES cout << "YES" << "\n"; return
#define NO cout << "NO" << "\n"; return
using ll = long long;
#ifdef LOCAL
#include <debugger>
#else
#define debug(...) 42
#endif
template <typename T> void chkmax(T &x, T y) { x = max(x, y); }
template <typename T> void chkmin(T &x, T y) { x = min(x, y); }
constexpr ll inf = 1e18;
map<pair<char, char>, int> mp;
void solve() {
string s1, s2; cin >> s1 >> s2;
int n = s1.size(), m = s2.size();
s1 = " " + s1;
s2 = " " + s2;
vector<char> all{'A', 'T', 'G', 'C'};
for(int i = 0; i < 4; i ++ ) {
for(int j = 0; j < 4; j ++ ) {
int x; cin >> x;
mp[{all[i], all[j]}] = x;
}
}
// cout << mp[{'G', 'C'}] << "\n";
ll x, y; cin >> x >> y;
vector<vector<array<ll, 3> > > f(n + 1, vector<array<ll, 3> >(m + 1, {-inf, -inf, -inf}));
for(int i = 1; i <= n || i <= m; ++ i ) {
if(i <= m) {
f[0][i][1] = -x - y * (i - 1);
}
if(i <= n) {
f[i][0][2] = -x - y * (i - 1);
}
}
f[0][0][0] = 0;
//f[i][j][0] 表示s1匹配了i个, s2匹配了j个,并且当前状态为两个字符
//f[i][j][1] 表示s1匹配了i个, s2匹配了j个,并且当前状态为s1是空格,s2是字符
//f[i][j][2] 表示s1匹配了i个, s2匹配了j个,并且当前状态为s1是字符,s2是空格
for (int i = 1; i <= n; i ++ ) {
for (int j = 1; j <= m; j ++ ) {
//
//
f[i][j][0] = max({f[i - 1][j - 1][0], f[i - 1][j - 1][1], f[i - 1][j - 1][2]}) + mp[{s1[i], s2[j]}];
f[i][j][1] = max({f[i][j - 1][0] - x, f[i][j - 1][1] - y, f[i][j - 1][2] - x});
f[i][j][2] = max({f[i - 1][j][0] - x, f[i - 1][j][1] - x, f[i - 1][j][2] - y});
// f[i][j][1] = max({f[i - 1][j][0], f[i - 1][j][2]});
// f[i][j][2] = max({f[i][j - 1][0], f[i][j - 1][1]});
// printf("%d %d -> %lld %lld %lld\n", i, j, f[i][j][0], f[i][j][1], f[i][j][2]);
// printf("f[%d][%d][%d] = %lld\n", i, j, )
}
}
// cout << f[1][1][1] << "\n";
cout << max({f[n][m][0], f[n][m][1], f[n][m][2]}) << "\n";
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int T = 1; //cin >> T;
while(T -- ) solve();
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现