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;
}

浙公网安备 33010602011771号