题解:P11444 [Code+#6] 祖玛

· · 题解

好玩的区间 dp。

竟然是这题题解区的第一篇题解诶。

分析

根据套路,先设 f_{l,r} 表示删完区间 [l,r] 内的数可获得的最大权值。但是容易发现区间 [l,r] 还可能与 [1,l-1] 中的数有联系,因为可能在删完 [l,r] 的一个前缀 [l,k] 时,[k+1,r][1,l-1] 可以拼接在一起,即 a_{l-1}=a_{k+1}

于是设 f_{l,r,x,p} 表示删完区间 [l,r] 内的数,且需要或不需要删掉 a_{l-1}p01),如果要删的话则删 x 个的最大权值,接下来转移方程便很好推了。

枚举断点 k,则有两种转移:

细节:

Code

#include <bits/stdc++.h>
using namespace std;
#define int long long
int a[105], f[105][105][105][2], mi, ma, tmp, k;

int dfs(int l, int r, int xuan, int p) {
    if (l > r) {
        if (xuan && (mi > xuan || xuan > ma))
            return -1000000000;
        tmp = max(tmp, xuan * xuan);
        return xuan * xuan;
    }
    if (f[l][r][xuan][p] > k)
        return f[l][r][xuan][p];
    if (xuan > ma)
        return 0;
    int ans = 0;
    for (int k = l; k <= r; k++)
        if (p && a[k] == a[l - 1])
            ans = max(ans, dfs(l, k - 1, 0, 0) + dfs(k + 1, r, xuan + 1, 1));
    for (int k = l; k <= r; k++)
        if ((!xuan || (mi <= xuan && xuan <= ma)))
            ans = max(ans, dfs(l, k - 1, 0, 0) + dfs(k + 1, r, 1, 1) + xuan * xuan);
    tmp = max(tmp, ans);
    return f[l][r][xuan][p] = ans;
}

signed main() {
    memset(f, -0x3f, sizeof(f));
    k = f[0][0][0][0];
    int n;
    cin >> n;
    for (int i = 1; i <= n; i++)
        cin >> a[i];
    cin >> mi >> ma;
    for (int i = 1; i <= n; i++)
        dfs(i + 1, n, 1, 1);
    tmp = max(tmp, dfs(1, n, 0, 0));
    cout << tmp;
}