CF1372E
由于是取平方和,所以有明显的结论:一定存在一种最优方案,第 $1$ 列是全 $1$ 的。
这个结论看似没什么用,但却可以反应出如下性质:
定义“可取的位置”为:此时其所在区间还没有 $1$ 的位置。那么答案必定是按照 某个优先级从大到小,逐列把列上所有“可取的位置”都变为 $1$。
拿样例解释一下,它优先取第一列,发现当前所有包含了形如 $(i,1)$ 的区间都是全 $0$ 的,所以贡献为 $4^2$;其次是最后一列,发现贡献也是 $4^2$;接着是第二列,发现第 $3$ 行的第二个区间、第 $4$ 行的第二个区间是全 $0$ 的,贡献是 $2^2$;最后是剩下的 $3,4$ 两列,贡献都是 $0^2$。所以答案是 $4^2+4^2+2^2+0^2+0^2$。
会发现上述性质反证法可得。
考虑使用区间 $\text{DP}$。$f_{l,r}$:满足 $l \leq l' \leq r' \leq r$ 的所有区间 $[l',r']$ 能得到的最大贡献;再钦定 $c_{l,r,i}$ 为:满足 $l \leq l' \leq i \leq r' \leq r$ 的区间对 $[l', r']$ 的个数。
转移显然,枚举 $[l,r]$ 中优先级最高的点 $i$:$$ f_{l,r} \gets f_{l,i-1}+f_{i+1,r}+c_{l,r,i} $$
但是现在还存在一个问题:没有完全被 $[l,r]$ 覆盖的区间是否可能对 $i$ 产生贡献?
其实不然。当我们转移到一个区间时,端点处要不是边界,就是优先级比它高的点。所以不存在这种情况。
#include <bits/stdc++.h>
#define FL(i, a, b) for(int i = (a); i <= (b); i++)
#define FR(i, a, b) for(int i = (a); i >= (b); i--)
using namespace std;
const int N = 110;
int n, m, f[N][N], c[N][N][N];
int main(){
scanf("%d%d", &n, &m);
FL(i, 1, n){
int len, l, r; scanf("%d", &len);
FL(j, 1, len){
scanf("%d%d", &l, &r);
FL(k, l, r) c[l][r][k]++;
}
}
FL(len, 1, m) FL(l, 1, m - len + 1){
int r = l + len - 1;
FL(i, l, r){
c[l][r][i] += c[l + 1][r][i] + c[l][r - 1][i] - c[l + 1][r - 1][i];
f[l][r] = max(f[l][r], f[l][i - 1] + f[i + 1][r] + c[l][r][i] * c[l][r][i]);
}
}
printf("%d\n", f[1][m]);
return 0;
}