P1880 [NOI1995]石子合併
阿新 • • 發佈:2020-09-19
做過類似的,不過這題稍微有點不一樣:是環不是鏈。
只要把鏈複製一遍原來的鏈的後面,就可以化環為鏈了。
注意題目求的是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; }