CF1146G 题解
CF1146G 题解
给一个 DP
的做法。
题意:
对长 \(n\) 的序列 \(a\),记 \(f(a)=(\sum\limits_{i=1}^na_i^2)+(\sum\limits_{i=1}^mc_i[\max\limits_{j=l_i}^{r_i}a_j>x_i])\),求 \(\max\limits_{\forall i\in[1,n],a_i\in[0,h]}f(a)\)。
做法:
显然需要区间 DP
,设 \(f(l,r)\) 代表区间 \([l,r]\) 内的最大收益。
考虑如何处理对区间高度 \(\max\) 的限制,我们可以枚举区间内最大值,来将问题划分成一些子问题。
例如,如果我们想计算 \(f(l,r)\) 的值,我们可以枚举二元组 \((p,z)\),代表 \(\max\limits_{i=l}^ra_i=a_p=z\),
那么对所有满足 \(l\le l_i\le p\le r_i\le r,x_i<z\) 的分区限制 \(i\),\(c_i\) 的罚款是必须要付的,
而对于其他的分区限制是否需要缴纳罚款,还是暂时不能确定的,但我们可以发现,
此时对于区间 \([l,p-1]\) 和 \([p+1,r]\),这两段区间是两个子问题,唯一的限制是最大值 \(a_p=z\) 带来的,
即要求 \(\max\limits_{i=l}^{p-1}a_i\) 和 \(\max\limits_{i=p+1}^ra_i\) 都不超过 \(z\),那么我们可以在 DP
状态中记录 \(z\) 这一维,来处理这个限制。
即,记 \(f(l,r,z)\) 代表区间 \([l,r]\) 内,满足 \(\max\limits_{i=l}^ra_i\le z\) 的最大收益。
此时,区间 \([l,p-1]\) 和 \([p+1,r]\) 内的最大收益,就可以用 \(\max\limits_{x\le z}f(l,p-1,x)\) 和 \(\max\limits_{x\le z}f(p+1,r,x)\) 来表示,
我们维护 DP
数组的前缀最大值,即可做到 \(O(n^4)\) 转移。
code:
#include<bits/stdc++.h>
#define ckmax(a, b) ((a) = max((a), (b)))
#define rep(i, a, b) for (int i = (a); i <= (b); i++)
using namespace std;
int read() {/*快读*/}
const int N (55);
int n, m, h, f[N][N][N], lim[N][N][N][N];
struct Node { int l, r, x, c; } q[N];
int dp (int l, int r, int x, int res = -2e9) {
if (x < 0 || l > r) return 0;
if (f[l][r][x] != -1) return f[l][r][x];
rep (p, l, r) ckmax (res, dp (l, p - 1, x) + dp (p + 1, r, x) + x * x + lim[l][r][p][x]);
return f[l][r][x] = max (res, dp (l, r, x - 1));
}
int main() {
n = read(), h = read(), m = read();
rep (i, 1, m) {
int l = read(), r = read(), x = read(), c = read();
q[i].l = l, q[i].r = r, q[i].x = x, q[i].c = c;
}
rep (l, 1, n) rep (r, l, n) rep (p, l, r) rep (i, 1, m) {
int L = q[i].l, R = q[i].r, X = q[i].x, C = q[i].c;
if (l <= L && L <= p && p <= R && R <= r) lim[l][r][p][X + 1] -= C;
}
rep (l, 1, n) rep (r, l, n) rep (p, l, r) rep (x, 1, h) lim[l][r][p][x] += lim[l][r][p][x - 1];
memset (f, -1, sizeof(f)), cout << dp (1, n, h); return 0;
}