题目描述
在一个圆形操场的四周摆放 (N) 堆石子,现要将石子有次序地合并成一堆.规定每次只能选相邻的2堆合并成新的一堆,并将新的一堆的石子数,记为该次合并的得分。
试设计出一个算法,计算出将(N)堆石子合并成 (1) 堆的最小得分和最大得分。
输入格式
数据的第 (1) 行是正整数 (N),表示有 (N) 堆石子。
第 (2) 行有 (N) 个整数,第 (i) 个整数 (a_i) 表示第 (i) 堆石子的个数。
输出格式
输出共 (2) 行,第 (1) 行为最小得分,第 (2) 行为最大得分。
输入输出样例
输入 #1
4
4 5 9 4
输出 #1
43
54
说明/提示
(1≤N≤100,0≤ai≤200。)
【思路】
拆环,把链的长度延长到(2n), 区间dp做法,最后枚举左端点取其中最大/最小的结果。
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <list>
#include <map>
#include <iostream>
#include <iomanip>
#include <queue>
#include <set>
#include <stack>
#include <string>
#include <unordered_map>
#include <vector>
#define LL long long
#define inf 0x3f3f3f3f
#define INF 0x3f3f3f3f3f3f
#define PI 3.1415926535898
#define F first
#define S second
#define endl '
'
#define lson rt << 1
#define rson rt << 1 | 1
#define f(x, y, z) for (LL x = (y), __ = (z); x < __; ++x)
#define _rep(i, a, b) for (LL i = (a); i <= (b); ++i)
using namespace std;
const int maxn = 207;
const int maxm = 2e4 + 7;
const int mod = 19650827;
int n;
int a[maxn], dpmx[maxn][maxn], dpmn[maxn][maxn], sum[maxn];
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cin >> n;
memset(dpmx, 0, sizeof(dpmx));
memset(dpmn, inf, sizeof(dpmn));
_rep(i, 1, n)
{
cin >> a[i];
a[i + n] = a[i];
}
_rep(i, 1, 2 * n)
{
sum[i] = sum[i - 1] + a[i];
dpmn[i][i] = 0;
}
_rep(len, 1, n)
{
_rep(l, 1, n * 2 - len)
{
int r = l + len;
_rep(k, l, r - 1)
{
dpmx[l][r] = max(dpmx[l][r], dpmx[l][k] + dpmx[k + 1][r] + sum[r] - sum[l - 1]);
dpmn[l][r] = min(dpmn[l][r], dpmn[l][k] + dpmn[k + 1][r] + sum[r] - sum[l - 1]);
}
}
}
int mx = 0, mn = inf;
_rep(i, 1, n)
{
mx = max(mx, dpmx[i][i + n - 1]);
mn = min(mn, dpmn[i][i + n - 1]);
}
cout << mn << endl << mx << endl;
}