CF1832F Zombies题解

首先把题目转化成求交的最大值,然后假设已经确定了生成的区间,那么考虑按中点排序,然后对于每一个初始区间,显然是取中点离自己中点最近的区间,然后又注意到对于一个目标区间,必然存在一个初始区间是的左端点或右端点重合,否则可以移动使之更优,所以最多只有 \(\Theta(n)\) 个可能的目标区间,于是就把原问题转换成为了将排过序的初始区间划分为最多 \(k\) 段,然后每一段用一个目标区间来覆盖,记 \(w(l,r)\) 表示将 \(l\sim r\) 用一个初始区间覆盖需要的最大价值,注意到有决策单调性,维护 \(bst(l,r)\) 表示使用的是哪一个目标区间,算 \(w(l,r)\) 的时候枚举 \(bst(l,r-1)\sim bst(l+1,r)\) 即可,然后就是设 \(f_{i,j}\) 表示前 \(i\) 个数,划分了 \(j\) 次的最大价值,注意到价值函数满足四边形不等式(作者不会证),于是分治求解即可。

代码:

#include <bits/stdc++.h>
#pragma GCC optimize("Ofast", "inline")
#define int long long
using namespace std;
const int N = 2020;
int n, k, x, m, t, ans;
int cost[N << 1][N];
struct Range{
    int l, r;
    void rd() {scanf("%lld%lld", &l, &r);}
    Range() {}
    Range(int _l, int _r)
        : l(_l), r(_r) {}
    bool operator<(const Range &_)const{
        return l + r < _.l + _.r;
    }
    int f(Range _) {
        return max(0ll, min(r, _.r) - max(l, _.l));
    }
} a[N], b[N << 1];
void initb() {
    for (int i = 1, flg; i <= n; ++i) {
        flg = 0;
        for (int j = 1; j < i; ++j) flg |= (a[j].l == a[i].l || a[j].r - m == a[i].l);
        if (!flg && a[i].l + m <= x) b[++t] = Range(a[i].l, a[i].l + m);
        flg = 0;
        for (int j = 1; j < i; ++j) flg |= (a[j].l + m == a[i].r || a[j].r == a[i].r);
        if (!flg && a[i].r - m > -1) b[++t] = Range(a[i].r - m, a[i].r);
    }
    bool flg = 0;
    for (int i = 1; i <= n; ++i) flg |= (a[i].l + m == x || a[i].r == x);
    if (!flg) b[++t] = Range(x - m, x);
    flg = 0;
    for (int i = 1; i <= n; ++i) flg |= (a[i].l == 0 || a[i].r - m == 0);
    if (!flg) b[++t] = Range(0, m);
    sort(b + 1, b + t + 1);
    for (int i = 1; i <= t; ++i) for (int j = 1; j <= n; ++j)
        cost[i][j] = cost[i][j - 1] + b[i].f(a[j]);
    return;
}
int calc(int x, int l, int r) {return cost[x][r] - cost[x][l - 1];}
int bst[N][N], cst[N][N], f[N][N];
void dp(int l, int r, int L, int R, int d) {
    if (l > r || L > R) return;
    int mid = (l + r) >> 1, bt = 0;
    for (int i = L; i <= R; ++i) if (f[d - 1][i - 1] + cst[i][mid] > f[d][mid])
        f[d][mid] = f[d - 1][i - 1] + cst[i][mid], bt = i;
    dp(l, mid - 1, L, bt, d), dp(mid + 1, r, bt, R, d);
    return;
}
signed main() {
    scanf("%lld%lld%lld%lld", &n, &k, &x, &m), ans = n * (x - m);
    for (int i = 1; i <= n; ++i) a[i].rd(), ans -= a[i].r - a[i].l;
    sort(a + 1, a + n + 1), initb();
    memset(cst, -0x3f, sizeof cst);
    for (int i = 1; i <= n; ++i) for (int j = max(bst[i - 1][i - 1], 1ll); j <= t; ++j)
        if (calc(j, i, i) > cst[i][i]) cst[i][i] = calc(j, i, i), bst[i][i] = j;
    for (int len = 2; len <= n; ++len) {
        for (int i = 1, j = len; j <= n; ++i, ++j) {
            for (int o = bst[i][j - 1]; o <= bst[i + 1][j]; ++o)
                if (calc(o, i, j) > cst[i][j]) cst[i][j] = calc(o, i, j), bst[i][j] = o;
        }
    }
    f[0][0] = 0;
    for (int i = 1; i <= k; ++i) dp(1, n, 1, n, i);
    printf("%lld\n", ans + f[k][n]);
    return 0;
}
posted @ 2024-10-30 13:55  yaoyanfeng  阅读(10)  评论(0)    收藏  举报