做过类似的,不过这题稍微有点不一样:是环不是链。
只要把链复制一遍原来的链的后面,就可以化环为链了。
注意题目求的是N堆石子合并,枚举区间长度的时候依然是从2枚举到N。
int a[maxn];
int b[maxn];
//前缀和
int dp1[maxn][maxn], dp2[maxn][maxn];
int main()
{
int N; cin >> N;
memset(dp1, INF, sizeof(dp1));
memset(dp2, -INF, sizeof(dp2));
for (int i = 1; i <= N; i++) {
dp1[i][i] = dp2[i][i] = dp1[N + i][N + i] = dp2[N + i][N + i] = 0;
}
//自己和自己合并得分为0
for (int i = 1; i <= N; i++) {
cin >> a[i];
a[i + N] = a[i];
}
//化环为链
for (int i = 1; i <= N + N - 1; i++) {
b[i] = b[i - 1] + a[i];
}
for (int len = 2; len <= N; len++) {
//枚举长度
for (int l = 1; l <= N+N - len + 1; l++) {
//枚举左端点l
int r = l + len - 1;
for (int spl = l; spl <= r - 1; spl++) {
//枚举分割点split
//表示在spl堆与spl+1堆之间分割
dp1[l][r] = min(dp1[l][r], dp1[l][spl] + dp1[spl + 1][r]);
dp2[l][r] = max(dp2[l][r], dp2[l][spl] + dp2[spl + 1][r]);
}
dp1[l][r] += b[r] - b[l - 1];
dp2[l][r] += b[r] - b[l - 1];
}
}
//长度为N的区间全扫一遍取最大/最小值
int mmax = -1;
int mmin = INF;
for (int i = 1; i <= N; i++) {
mmin = min(mmin, dp1[i][i + N - 1]);
mmax = max(mmax, dp2[i][i + N - 1]);
}
cout << mmin << endl << mmax << endl;
return 0;
}