#區間dp,離散#D 弱者對決
阿新 • • 發佈:2020-12-02
分析
設\(dp[i][j][x]\)表示當前區間為\([i,j]\),最小值為\(x\)的最大總分,
狀態轉移方程可以用字尾最大值優化到\(O(n^3m)\),主要難點是輸出方案
字尾最大值需要記錄是在哪個位置取得最大值
程式碼
#include <cstdio> #include <cctype> #include <algorithm> #define rr register using namespace std; const int N = 4011, M = 61; int n, m, tot, c[N], a[N], b[N], L[N], R[N]; int dp[M][M][N], f[M][M][N], p[M][M][N], pf[M][M][N]; inline signed iut() { rr int ans = 0; rr char c = getchar(); while (!isdigit(c)) c = getchar(); while (isdigit(c)) ans = (ans << 3) + (ans << 1) + (c ^ 48), c = getchar(); return ans; } inline void print(int ans) { if (ans > 9) print(ans / 10); putchar(ans % 10 + 48); } inline void calc(int l, int mid, int r) { for (rr int i = 1; i <= tot; ++i) c[i] = 0; for (rr int i = 1; i <= m; ++i) if (l <= L[i] && L[i] <= mid && mid <= R[i] && R[i] <= r) ++c[a[i]]; } inline void dfs(int l, int r, int now) { rr int mid = p[l][r][now]; if (l < mid) dfs(l, mid - 1, pf[l][mid - 1][now]); printf("%d ", b[now]); if (mid < r) dfs(mid + 1, r, pf[mid + 1][r][now]); } signed main() { freopen("baddream.in", "r", stdin); freopen("baddream.out", "w", stdout); n = iut(), m = iut(); for (rr int i = 1; i <= m; ++i) L[i] = iut(), R[i] = iut(), b[i] = a[i] = iut(); sort(b + 1, b + 1 + m), tot = unique(b + 1, b + 1 + m) - b - 1; for (rr int i = 1; i <= m; ++i) a[i] = lower_bound(b + 1, b + 1 + tot, a[i]) - b; for (rr int i = n; i >= 1; --i) for (rr int j = i; j <= n; ++j) { for (rr int k = i; k <= j; ++k) { calc(i, k, j); for (rr int o = tot, sum = 0; o; --o) { sum += c[o]; rr int now = dp[i][k - 1][o] + dp[k + 1][j][o] + sum * b[o]; if (now >= f[i][j][o]) f[i][j][o] = now, p[i][j][o] = k; } } for (rr int o = tot; o; --o) if (f[i][j][o] >= dp[i][j][o + 1]) dp[i][j][o] = f[i][j][o], pf[i][j][o] = o; else dp[i][j][o] = dp[i][j][o + 1], pf[i][j][o] = pf[i][j][o + 1]; } printf("%d\n", dp[1][n][1]); dfs(1, n, pf[1][n][1]); return 0; }