1 条题解
-
0
区间 DP 好题。因为 具体值不重要,只关心相对大小,所以离散化 。设 表示区间 最小值不小于为 的答案。由于要输出方案所以记录 表示 的区间最小值取了 ,以及 表示 的分割点,这说明 由 和 转移而来。
转移枚举断点 ,则贡献为 $f_{l,r,x}=cx+\max_{k\in [l,r]}f_{l,k-1,x}+f_{k+1,r,x}$,其中 是满足 的 的个数,可以在枚举 的时候 预处理。注意还要和 取 。时间复杂度 。
const int N = 50 + 5; const int M = 4e3 + 5; int n, m, a[M], b[M], c[M], d[M]; int ans[N], f[N][N][M], buc[N][N]; pii tr[N][N][M]; void dfs(int l, int r, int p) { if(l > r) return; pii it = tr[l][r][p]; ans[it.se] = d[it.fi]; dfs(l, it.se - 1, it.fi), dfs(it.se + 1, r, it.fi); } bool Med; int main(){ cin >> n >> m; for(int i = 1; i <= m; i++) cin >> a[i] >> b[i] >> c[i], d[i] = c[i]; sort(d + 1, d + m + 1); for(int i = 1; i <= m; i++) c[i] = lower_bound(d + 1, d + m + 1, c[i]) - d; for(int i = m; i; i--) { for(int j = 1; j <= m; j++) if(c[j] == i) for(int l = 1; l <= a[j]; l++) for(int r = b[j]; r <= n; r++) buc[l][r]++; for(int len = 1; len <= n; len++) for(int l = 1, r = len; r <= n; l++, r++) { f[l][r][i] = f[l][r][i + 1], tr[l][r][i] = tr[l][r][i + 1]; for(int p = l; p <= r; p++) { int coef = buc[l][r] - buc[l][p - 1] - buc[p + 1][r]; int v = f[l][p - 1][i] + f[p + 1][r][i] + coef * d[i]; if(v > f[l][r][i]) f[l][r][i] = v, tr[l][r][i] = {i, p}; } if(tr[l][r][i].fi == 0) tr[l][r][i] = {i, l}; } } cout << f[1][n][1] << endl, dfs(1, n, 1); for(int i = 1; i <= n; i++) cout << ans[i] << " "; return 0; }
- 1
信息
- ID
- 6045
- 时间
- 2000ms
- 内存
- 356MiB
- 难度
- 10
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者