CF150D Mission Impassable

Div. 1 D. Mission Impassable

简要题意

给定一个字符串,删去一个长度为 \(k\) 的回文串的贡献为 \(a_k\),问这个字符串可以获得的最大贡献。

思路

由于答案的形态一定是消去若干段区间,因此可以想到区间 dp。而又由于题目说明了代价和回文串的长度强相关,于是考虑把长度这一维塞到状态里。

设 \(dp_{i, j, k}\) 表示把 \([i, j]\) 消到只剩长度为 \(k\) 的回文串可以获得的最大贡献。对于状态 \((i, j, k)\),其可以继续分治为 \((i, l - 1, 0), (l, r, k), (r + 1, j, 0)\)。而这种分治形式又等价于枚举一个分界点 \(p\),使得 \(l \le p, r > p\),所以该分治可以继续简化成 \((i, p, 0), (p + 1, j, k)\) 或 \((i, p, k), (i, p + 1, 0)\)。至于对 \(k\) 的转移,我们只需要处理其在端点的情况即可(因为其它转移都被第一种包含了),即 \((i + 1, j - 1, k - 2) \to (i, j, k)\)。最后是对某个区间选或不选的转移,可以额外子序列 dp。

代码:

#include <bits/stdc++.h>
#define int long long
using namespace std;

const int N = 155;
int n, a[N], g[N], f[N][N], dp[N][N][N];
string s;

signed main() {
    ios_base :: sync_with_stdio(NULL);
    cin.tie(nullptr);
    cout.tie(nullptr);

    memset(f, ~ 0x3f, sizeof f);
    memset(dp, ~ 0x3f, sizeof dp);

    cin >> n;
    for(int i = 1 ; i <= n ; ++ i)
        cin >> a[i];
    cin >> s;

    s = " " + s;

    for(int i = 1 ; i <= n ; ++ i) {
        dp[i][i][1] = 0;

        if(a[1] >= 0) f[i][i] = a[1];
        else f[i][i] = -2e18;

        dp[i][i][0] = f[i][i];
    }

    for(int i = 1 ; i < n ; ++ i) {
        if(a[1] >= 0) dp[i][i + 1][1] = a[1], f[i][i + 1] = a[1] * 2;
        else dp[i][i + 1][1] = f[i][i + 1] = -2e18;

        if(s[i] == s[i + 1]) {
            dp[i][i + 1][2] = 0;
            if(a[2] >= 0) f[i][i + 1] = max(f[i][i + 1], a[2]);
        }

        dp[i][i + 1][0] = f[i][i + 1];
    }

    for(int len = 3 ; len <= n ; ++ len) {
        for(int i = 1 ; i <= n - len + 1 ; ++ i) {
            int j = i + len - 1;

            f[i][j] = -2e18;

            for(int k = 1 ; k <= n ; ++ k) {
                if(s[i] == s[j]) dp[i][j][k] = dp[i + 1][j - 1][k - 2];
                else dp[i][j][k] = -2e18;

                for(int l = i ; l < j ; ++ l)
                    dp[i][j][k] = max(dp[i][j][k], max(dp[i][l][k] + f[l + 1][j], f[i][l] + dp[l + 1][j][k]));

                if(a[k] >= 0) f[i][j] = max(f[i][j], dp[i][j][k] + a[k]);
            }

            dp[i][j][0] = f[i][j];
        }
    }

    for(int i = 1 ; i <= n ; ++ i) {
        g[i] = g[i - 1];

        for(int j = 1 ; j <= i ; ++ j)
            g[i] = max(g[i], g[j - 1] + f[j][i]);
    }
    
    cout << g[n];

    return 0;
}
posted @ 2026-10-04 23:12  endswitch  阅读(4)  评论(0)    收藏  举报