挺简单一个题,也不需要优化,洛谷的题解非得写那么麻烦。
题目描述
在一个 圆形 操场的四周摆放
N
N
N 堆石子,现要将石子有次序地合并成一堆,规定每次只能选相邻的
2
2
2 堆合并成新的一堆,并将新的一堆的石子数,记为该次合并的得分。
试设计出一个算法,计算出将
N
N
N 堆石子合并成
1
1
1 堆的最小得分和最大得分。
输入 数据的第
1
1
1 行是正整数
N
N
N,表示有
N
N
N 堆石子。
第
2
2
2 行有
N
N
N 个整数,第
i
i
i 个整数
a
i
a_i
ai? ? 表示第
i
i
i 堆石子的个数。
输出 输出共
2
2
2 行,第
1
1
1 行为最小得分,第
2
2
2 行为最大得分。
输入输出样例 输入
4
4 5 9 4
输出
43
54
解题过程
注意,此题是 环形 区间。 请保证已经做过 P1775 石子合并(弱化版) 。 由线变环,我们考虑将原来的区间长度扩大一倍至
2
n
2n
2n,同时记录前缀和的
s
u
m
sum
sum 数组相应扩展至
2
n
2n
2n, 但记录
d
p
[
i
]
[
j
]
dp[i][j]
dp[i][j] 的子区间长度
l
e
n
len
len 依旧处于
[
1
,
n
]
[1, n]
[1,n] 之间。 这样返回的不能是
d
p
[
1
]
[
n
]
dp[1][n]
dp[1][n],而是在
d
p
[
i
,
n
]
,
d
p
[
i
+
1
]
[
n
+
1
]
,
d
p
[
i
+
2
]
[
n
+
2
]
.
.
.
d
p
[
n
]
[
2
n
]
dp[i, n], dp[i+1][n+1],dp[i + 2][n+2]...dp[n][2n]
dp[i,n],dp[i+1][n+1],dp[i+2][n+2]...dp[n][2n] 区间内找到一个最小/最大值。 代码显而易见。
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int len = 810;
const int INF = 0x3f3f3f;
int n, a[len], sum[len], dp1[len][len], dp2[len][len];
void ans(){
memset(dp1, 0, sizeof(dp1));
memset(dp2, 0, sizeof(dp2));
for(int len = 1; len <= n; len++){
for(int i = 1; i <= 2 * n - len; i++){
int j = i + len;
dp1[i][j] = INF;
dp2[i][j] = -INF;
for(int k = i; k < j; k++){
dp1[i][j] = min(dp1[i][j], dp1[i][k] + dp1[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 maxx = -INF;
int minn = INF;
for(int i = 1; i <= n; i++){
minn = min(minn, dp1[i][i + n - 1]);
maxx = max(maxx, dp2[i][i + n - 1]);
}
cout << minn << endl << maxx << endl;
}
signed main(){
cin >> n;
for(int i = 1; i <= n; i++) {
cin >> a[i];
sum[i] = sum[i - 1] + a[i];
}
for(int i = n + 1; i <= 2 * n; i++){
sum[i] = sum[i - 1] + a[i - n];
}
ans();
return 0;
}
|