题目
思路
本题的数据量很小。。。就能让我很偷懒地使用一种投机取巧的方法。。
本题如果去掉是个环,那就是个普通的不能再普通的区间DP,参考区间DP例题矩阵链乘。我也刚开始没看到是个环,写完了样例都过不了。。
后来想了一段时间,想过用DAG模型,但是总感觉还是脱离不了区间DP,难不成把DAG魔改一下?。。
最后突然想到,其实可以把环暴力转换成序列,就是一个环的序列形式最多有它的长度那么多种。都暴力枚举出来,然后依次做区间DP,最后
O(n3)
O
(
n
3
)
足够应付本题的数据量。。
但我觉得我还是应该看看正解大佬们是什么样的。。
好吧都是这么写的。。。
代码
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#define _for(i,a,b) for(int i = (a); i<(b); i++)
#define _rep(i,a,b) for(int i = (a); i<=(b); i++)
using namespace std;
const int INF = 1 << 28;
const int maxn = 100 + 10;
int n, A[maxn], B[maxn], S[maxn], maxd[maxn][maxn], mind[maxn][maxn];
int main() {
scanf("%d", &n);
_rep(i, 1, n) scanf("%d", &B[i]);
int minans = INF, maxans = -INF;
_for(v, 0, n) {
// 生成数组A
_rep(i, 1, n) {
if (v + i <= n) A[i+v] = B[i];
else A[(i + v) % n] = B[i];
}
// 计算前缀和S
_rep(i, 1, n) S[i] = S[i - 1] + A[i];
// 区间DP的特殊枚举顺序
int j;
_rep(l, 1, n)
_rep(i, 1, n) {
j = i + l;
if (j > n) continue;
maxd[i][j] = 0;
mind[i][j] = INF;
_rep(k, i, j - 1) {
maxd[i][j] = max(maxd[i][j], maxd[i][k] + maxd[k + 1][j] + S[j] - S[i - 1]);
mind[i][j] = min(mind[i][j], mind[i][k] + mind[k + 1][j] + S[j] - S[i - 1]);
}
}
minans = min(minans, mind[1][n]);
maxans = max(maxans, maxd[1][n]);
}
printf("%d\n%d\n", minans, maxans);
return 0;
}