Description
给出 (n le 15) 个数字,不改变它们的相对位置,在中间加入 (k) 个乘号和 ((n-k-1)) 个加号,括号随便加,使最终结果尽量大。
Solution
说好不写题解了的老龄选手怎么又来灌水?突然被人甩了个题,难顶
网上有大量题解都假设了,最优解一定可以表示为若干段和的乘积,但在有 0 存在的情况下显然存在反例
解决方案是,放弃这个假设,但是最优子结构仍然可以使用
仍然用 (f[i][j][k]) 表示区间 ([i,j]) 中添加了 (k) 个乘号的方案数
转移时分别考虑用加号连接和乘号连接的情况即可
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 1e2 + 5;
int n, K;
int a[N];
int f[N][N][N];
signed main()
{
cin >> n >> K;
for (int i = 0; i < n; i++)
cin >> a[i];
memset(f, -1, sizeof f);
for (int i = 0; i < n; i++)
for (int j = i; j < n; j++)
f[i][j][0] = a[j] + (j > i) * f[i][j - 1][0];
for (int l = 0; l < n; l++)
for (int i = 0, j = i + l; j < n; i++, j++)
for (int k = 0; k <= K; k++)
for (int m = i; m < j; m++)
for (int x = 0; x <= k; x++)
{
if (~f[i][m][x] && ~f[m + 1][j][k - x])
f[i][j][k] = max(f[i][j][k], f[i][m][x] + f[m + 1][j][k - x]);
if (x < k)
if (~f[i][m][x] && ~f[m + 1][j][k - x - 1])
f[i][j][k] = max(f[i][j][k], f[i][m][x] * f[m + 1][j][k - x - 1]);
}
cout << f[0][n - 1][K] << endl;
}