P1388题解

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

任何区间都可以分解成最终两个数相乘或相加的情况,考虑区间dp,又因为有乘法次数限制,我们套一个背包即可,很轻松写出转移方程。

\(dp_{l,r,k}\) 表示 \([l,r]\) 区间使用 \(k\) 次乘法所能获得的最大价值。

\[\begin{cases} dp_{l,r,0} = a[l] & l = r \\ dp_{l,r,k} = \max\limits_{1\le m < k} (\max\limits_{0\le u \le k} dp_{l,m,u} + dp_{m+1,r,k-u}, \max\limits_{0\le u < k} dp_{l,m,u} \times dp_{m+1,r,k-u-1}) & l < r \end{cases} \]

但是注意边界条件!因为 \(0\) 的存在乘法用的多不一定更优,乘法可能对答案产生负影响。我们要判断状态是否存在合法再转移,否则可能会使得答案最后使用的乘法变少,比答案更优。

#include <bits/stdc++.h>

using namespace std;

int dp[16][16][15];

int main() {
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    int n, k;
    cin >> n >> k;
    memset(dp, -1, sizeof dp);
    for (int i = 1; i <= n; ++i) cin >> dp[i][i][0];
    for (int len = 2; len <= n; ++len) {
        for (int l = 1; l + len - 1 <= n; ++l) {
            int r = l + len - 1;
            for (int m = l; m < r; ++m) {
                for (int K = 0; K <= k; ++K) {
                    for (int u = 0; u <= K; ++u) {
                        if (dp[l][m][u] >= 0 && dp[m + 1][r][K - u] >= 0)
                            dp[l][r][K] = max(dp[l][r][K],
                                              dp[l][m][u] + dp[m + 1][r][K - u]);
                        if (u != K && dp[l][m][u] >= 0 && dp[m + 1][r][K - u - 1] >= 0)
                            dp[l][r][K] = max(dp[l][r][K],
                                              dp[l][m][u] * dp[m + 1][r][K - u - 1]);
                    }
                }
            }
        }
    }
    cout << dp[1][n][k];
    return 0;
}

posted @ 2026-01-07 17:42  Jefferyzzzz  阅读(0)  评论(0)    收藏  举报