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