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;
}
posted @ 2023-07-25 13:05  徐子洋  阅读(8)  评论(0)    收藏  举报  来源