#include <bits/stdc++.h>
using namespace std;
#define mst(a, b) memset((a), (b), sizeof(a))
typedef long long ll;
const int maxn = 410;
const ll mod = 1e9 + 7;
const ll INF = 1e18;
const double eps = 1e-9;
int n;
int sum[maxn], a[maxn];
int dp[maxn][maxn], dp2[maxn][maxn];
int main() {
cin >> n;
for (int i = 0; i <= maxn; ++i) {
for (int j = 0; j <= maxn; ++j) {
dp[i][j] = 0x7fffffff;
}
}
for (int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
sum[i] = sum[i - 1] + a[i]; //前缀和
dp[i][i] = 0; //初始化,只有一堆的时候不需要代价
}
for (int i = n + 1; i <= 2 * n; ++i) {
a[i] = a[i - n];
sum[i] = sum[i - 1] + a[i];
dp[i][i] = 0;
}
for (int len = 2; len <= n; len++) //阶段:区间长度
for (int i = 1; i <= 2 * n; i++) {
//状态:左端点
int j = i + len - 1; //状态:右端点
if (j > 2 * n)
continue; //决策
// sum[j]-sum[i-1]是这一次合并花费的代价,for循环知识在i到j里面找一个最合适的组合方式
for (int k = i; k < j; k++) {
//找花费最小的
dp[i][j] = min(dp[i][j],
dp[i][k] + dp[k + 1][j] + sum[j] - sum[i - 1]);
//找花费最大的
dp2[i][j] = max(
dp2[i][j], dp2[i][k] + dp2[k + 1][j] + sum[j] - sum[i - 1]);
}
}
int maxn = 0, minn = 0x7fffffff;
for (int i = 1; i <= n; ++i) {
maxn = max(dp2[i][i + n - 1], maxn);
minn = min(dp[i][i + n - 1], minn);
}
printf("%d\n", minn);
printf("%d\n", maxn);
return 0;
}
洛谷P1880 [NOI1995] 石子合并(区间dp)
最新推荐文章于 2022-03-14 17:58:48 发布