|
|
#include <bits/stdc++.h>
|
|
|
using namespace std;
|
|
|
const int INF = 0x3f3f3f3f;
|
|
|
|
|
|
const int N = 410; // 注意开双倍空间
|
|
|
int a[N]; // 原始数组
|
|
|
int s[N]; // 前缀和
|
|
|
int f[N][N]; // 最小得分,从i堆合并到j堆的最小代价
|
|
|
int g[N][N]; // 最大得分,从i堆合并到j堆的最大代价
|
|
|
int n, m;
|
|
|
|
|
|
// 搜索出l~r的最小得分
|
|
|
int dfs1(int l, int r) { // 求出最小得分
|
|
|
int &v = f[l][r]; // 利用C++特性,定义一个v,简化代码
|
|
|
if (l == r) return v = 0; // l==r时返回0
|
|
|
if (v) return v; // 已保存的状态不必搜索
|
|
|
int res = INF; // 初始值赋为最大值以求最小值
|
|
|
// 枚举l~r之间的每个可能k,之所以k∈[l,r),可以看下面的递推关系式dfs1(k+1,r)决定了k最大是r-1
|
|
|
for (int k = l; k < r; k++)
|
|
|
res = min(res, dfs1(l, k) + dfs1(k + 1, r));
|
|
|
return v = res + s[r] - s[l - 1]; // 记录状态
|
|
|
}
|
|
|
|
|
|
// 搜索出l~r的最大得分
|
|
|
int dfs2(int l, int r) { // 求出最大得分
|
|
|
int &v = g[l][r]; // 利用C++特性,定义一个v,简化代码
|
|
|
if (l == r) return v = 0; // 若初始值为0可省略该句
|
|
|
if (v) return v; // l==r时返回0
|
|
|
int res = 0; // 初始值设为0
|
|
|
for (int k = l; k < r; k++)
|
|
|
res = max(res, dfs2(l, k) + dfs2(k + 1, r));
|
|
|
return v = res + s[r] - s[l - 1]; // 记录状态
|
|
|
}
|
|
|
|
|
|
int main() {
|
|
|
scanf("%d", &n);
|
|
|
// 破环成链
|
|
|
for (int i = 1; i <= n; i++) scanf("%d", &a[i]), a[i + n] = a[i];
|
|
|
// 前缀和
|
|
|
for (int i = 1; i <= 2 * n; i++) s[i] = s[i - 1] + a[i];
|
|
|
|
|
|
// 搜索出1-2*n的最小得分
|
|
|
dfs1(1, 2 * n);
|
|
|
|
|
|
// 搜索出1-2*n的最大得分
|
|
|
dfs2(1, 2 * n);
|
|
|
|
|
|
int ans1 = INF, ans2 = 0;
|
|
|
for (int i = 1; i <= n; i++) {
|
|
|
ans1 = min(f[i][n + i - 1], ans1); // 选出最小答案
|
|
|
ans2 = max(g[i][n + i - 1], ans2); // 选出最大答案
|
|
|
}
|
|
|
printf("%d \n%d", ans1, ans2);
|
|
|
return 0;
|
|
|
}
|