题目大意
环形队列上有 $n$ 堆石子,可以把相邻的两堆合成一堆,每次合并的得分是新一堆的石子数。
求最终分数的最小值和最大值。
分析
考虑 $dp(i,j)$ 是将区间 $[i,j]$ 的石子全部合并的最大值。于是状态转移方程为
$$ dp(i,j) = \max_{i \leqslant k \leqslant j}(dp(i,k) + dp(k+1,j) + s(i,j)) $$
其中 $s(i,j)$ 是 $[i,j]$ 中所有石子数。
然而不能通过先 $i$ 再 $j$ 再 $k$ 的循环来递推,运算顺序值得注意。
细节:前缀和、循环开两倍。
int dmax[205][205], dmin[205][205];
int f[205], s[205];
int main() {
int n = rr();
for (ll i = 1; i <= n; i++)
f[i + n] = f[i] = rr();
for (ll i = 1; i <= n * 2; i++)
s[i] = s[i - 1] + f[i];
for (ll len = 2; len <= n; len++) {
for (ll i = 1; i <= 2 * n - len + 1; i++) {
int j = i + len - 1;
int tmax = 0, tmin = 0x3f3f3f3f;
int ss = s[j] - s[i - 1];
for (ll k = i; k <= j - 1; k++) {
tmax = max(tmax, dmax[i][k] + dmax[k + 1][j] + ss);
tmin = min(tmin, dmin[i][k] + dmin[k + 1][j] + ss);
}
dmax[i][j] = tmax;
dmin[i][j] = tmin;
}
}
int mmin = 0x3f3f3f3f, mmax = 0;
for (ll p = 0; p <= n - 1; p++) {
mmin = min(mmin, dmin[p + 1][p + n]);
mmax = max(mmax, dmax[p + 1][p + n]);
}
printf("%d\n%d\n", mmin, mmax);
return 0;
}