P4059题解

传送门:https://www.luogu.com.cn/problem/P4059

去掉连续段贡献即是经典的编辑字符问题,用 dp 解决。考虑在状态上加上是否在当前位置后加了空格,由于两个序列在相同位置有空格显然不优,因为剔除后结果仍然没有发生改变,因此只需要三种状态,也意味着只需要 dp 两个序列尾部即可。

\(dp_{i,j,0/1/2}\) 分别表示计算到 \(A\)\(i\) 位,\(B\)\(j\) 位,且 \(A\)\(B\) 末尾均没有空格/\(A\) 末尾有空格,\(B\) 末尾没有空格/\(A\) 末尾没有空格,\(B\) 末尾有空格。转移方程见代码:

#include <bits/stdc++.h>

const int N = 5e5 + 1;

using namespace std;

int mp[128], val[5][5], dp[3001][3001][3];

char s1[3001], s2[3001];

int main() {
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    cin >> s1 + 1 >> s2 + 1;
    int l1 = strlen(s1 + 1), l2 = strlen(s2 + 1);
    memset(dp, -0x3f, sizeof dp);
    for (int i = 1; i <= 4; ++i) for (int j = 1; j <= 4; ++j) cin >> val[i][j];
    mp['A'] = 1, mp['T'] = 2, mp['G'] = 3, mp['C'] = 4;
    int A, B;
    cin >> A >> B;
    dp[0][0][0] = 0;
    for (int i = 0; i <= l1; ++i) {
        for (int j = 0; j <= l2; ++j) {
            if (i && j)
                dp[i][j][0] = max(dp[i - 1][j - 1][0],
                                  max(dp[i - 1][j - 1][1], dp[i - 1][j - 1][2])) + val[mp[s1[i]]][mp[s2[j]]];
            if (j) dp[i][j][1] = max(max(dp[i][j - 1][0], dp[i][j - 1][2]) - A, dp[i][j - 1][1] - B);
            if (i) dp[i][j][2] = max(max(dp[i - 1][j][0], dp[i - 1][j][1]) - A, dp[i - 1][j][2] - B);
        }
    }
    cout << max(max(dp[l1][l2][0], dp[l1][l2][1]), dp[l1][l2][2]);
    return 0;
}
posted @ 2026-01-12 00:20  Jefferyzzzz  阅读(6)  评论(0)    收藏  举报