首页 > 其他分享 >LG-P4182 [USACO18JAN]Lifeguards P 题解

LG-P4182 [USACO18JAN]Lifeguards P 题解

时间:2022-12-02 20:34:02浏览次数:71  
标签:LG int 题解 最大值 队列 双端 区间 P4182 dp

LG-P4182 [USACO18JAN]Lifeguards P Solution

目录

更好的阅读体验戳此进入

解法本身题解区已经写的较为清楚了,这里主要对大多数题解都涉及到但均未证明的一个贪心策略进行感性证明,故前面的推导过程写的较为简略。

题面

给定 $ n $ 个左闭右开的区间,在范围 $ [0, 10^{9}] $ 内,最大化删去其中 $ k $ 个区间后剩下区间并起来的长度,求最大值。

$ 1 \le n \le 10^5, 1 \le k \le \min(100, n) $。

Solution

首先不难想到对于区间 $ [l_1, r_1), [l_2, r_2) $ 且 $ l_1 \le l_2 \land r_2 \le r_1 $ 那么删去 $ [l_2, r_2] $ 答案一定不变,于是可以直接全部删去,并将 $ k \leftarrow k - 1 $。

然后 DP 显然,也很好想到一个状态 $ dp(i, k) $ 表示考虑前 $ i $ 个区间,删去其中的 $ k $ 个的最优值,然后发现这玩意没有固定具体怎么删没法转移,然后就想到在原来的状态基础上钦定必须选择第 $ i $ 个区间,然后需要把区间优先按左端点,再按右端点排序,这样我们就会发现最开始去掉那些区间的作用了,去掉之后现在我们剩下的区间排序后一定满足对于 $ l $ 的升序一定也满足 $ r $ 升序,不满足的已经被我们删掉了。于是此时转移比较显然:$ dp(i, k) = \max{ dp(j, k - (i - j - 1)) + r_i - \max(l_i, r_j) }, j \in [i - k - 1, i - 1] $。这玩意复杂度显然是 $ O(nk^2) $ 的,显然不正确。

考虑优化,状态没什么可优化的,于是考虑优化转移,我们尝试提出来与转移时的 $ j $ 无关的项,令 $ \xi = i - k - 1 $,于是有 $ dp(i, k) = \max{ dp(j, j - \xi) + r_i - \max(l_i, r_j) }, j \in [i - k - 1, i - 1] $。也就是说我们要在 $ \xi = i - k - 1 $ 的前提下,换句话说就是以前的 $ dp $ 中前后索引的差为 $ \xi $ 的值中找到后面式子的最大值进行转移,这个东西简单分类讨论一下就是如果 $ l_i \ge r_j $(或者理解为区间无交)那么就是要最大化 $ dp(j, j - \xi) $。反之需要最大化 $ dp(j, j - \xi) - r_j $。

所以我们直接对前者维护一个最大值(因为我们的区间之间使有序的,所以如果对于之前的区间已经无交了,对于现在的一定也无交),后者则维护一个单调队列单调栈单调双端队列,每次处理时先把对应单调双端队列队头中所有不合法的,也就是不交的弹出然后更新不交区间里面的最大值。然后用交的和不交的里的最大值更新当前 $ dp $,每次处理完当前的 $ dp $ 就把当前的丢到对应的单调双端队列里,这时我们会按照双端队列直接把队尾不优于当前的直接丢掉而不是保留下来等待不交时更新不交的最大值,这个的原因我想了很久,感性地证明了一下,如下:

如果你仔细想一下就会发现这个算法有一点问题,首先我们在最初的找单调双端队列里面的队头不合法的值的时候,我们时按照 $ val $ 的大小,也就是 $ dp(j, j - \xi) - r_j $ 的大小维护的单调双端队列,但是我们更新不交最大值的时候需要的是与其不交区间里的最大值(废话),难道就不会存在一种情况,即队头的区间 $ val $ 更大,但是区间靠右,然而队头之后某个区间 $ val $ 较小却区间靠左,也就是存在一种情况单调优先队列的后面已经存在了不交的区间但是却被队头的相交区间阻挡了,这样的话我们难道不会少更新一些值吗?还有就是在把当前的 $ dp $ 压入单调双端队列的时候,我们会把队尾不优于当前值的直接踢掉,这个时候却没有考虑到在后面更新时这些区间可能会从相交变成不交,从而可能性地去更新不交的最大值,但是现在这被我们丢掉了,难道不会使答案更劣吗?

这几个问题困扰了我很久,完全没有头绪,直到发现了一个性质我才大概能感性理解这个贪心的正确性。

显然当我们转移的时候,如果转移的这个 $ j $ 是与 $ i $ 交的,那么最优的 $ j $ 一定是 $ l_j $ 最小的 $ j $,当然经过我们的处理之后同时也是 $ r_j $ 最小的。这个不难理解,因为我们处理过包含的区间,所以 $ i, j $ 相交那么最终这两段组成的区间一定是 $ [l_j, r_i) $,那么 $ l_j $ 尽量小一定更优,所以 $ j + 1, j + 2, \cdots, i - 1 $ 的区间都是没必要选的,选了也不会有任何贡献。

此时我们再回到刚才的考虑,我们的单调优先队列维护的是最大值,而最大值一定是 $ l $ 和 $ r $ 最小的,那么我们实际上也可以感性地认为更左的区间在单调双端队列里也更靠前,如果这个成立那么我们刚才的所有问题也就很显然是不需要考虑得了,这样的话我们弹出的队头一定是最先变得不交的,被丢掉的区间也一定是更劣的。

于是这个贪心(应该)是正确的。

当然上面这一大段证明都完全是我口糊的,不保证正确性,也不够理性和严谨,期待一个更严谨的证明。

Code

#define _USE_MATH_DEFINES
#include <bits/extc++.h>

#define PI M_PI
#define E M_E
#define npt nullptr
#define SON i->to
#define OPNEW void* operator new(size_t)
#define ROPNEW(arr) void* Edge::operator new(size_t){static Edge* P = arr; return P++;}

using namespace std;
using namespace __gnu_pbds;

mt19937 rnd(random_device{}());
int rndd(int l, int r){return rnd() % (r - l + 1) + l;}
bool rnddd(int x){return rndd(1, 100) <= x;}

typedef unsigned int uint;
typedef unsigned long long unll;
typedef long long ll;
typedef long double ld;

template< typename T = int >
inline T read(void);

struct Line{
    int l, r;
    friend const bool operator < (const Line &a, const Line &b){if(a.l == b.l)return a.r < b.r; return a.l < b.l;}
}line[110000];
list < Line > _line;
int N, K;
int cnt(0);
struct Status{int idx; int val;};
deque < Status > bst[110000];
int mx[110000];
int dp[110000][110];

int main(){
    N = read(), K = read();
    for(int i = 1; i <= N; ++i){
        int l = read(), r = read();
        _line.emplace_back(Line{l, r});
    }_line.sort();
    for(auto it = next(_line.begin()); it != _line.end();)
        if(it->r <= prev(it)->r)it = _line.erase(it), --K; else ++it;
    for(auto ln : _line)line[++cnt] = ln;
    N = cnt; K = max(0, K);
    for(int i = 1; i <= N; ++i){
        for(int k = 0; k <= min(i - 1, K); ++k){
            int xi = i - k - 1;
            while(!bst[xi].empty() && line[bst[xi].front().idx].r < line[i].l){
                auto tp = bst[xi].front(); bst[xi].pop_front();
                mx[xi] = max(mx[xi], tp.val + line[tp.idx].r);
            }
            dp[i][k] = max({
                dp[i][k],
                mx[xi] + line[i].r - line[i].l,
                bst[xi].empty() ? -1 : bst[xi].front().val + line[i].r
            });
            int val = dp[i][k] - line[i].r;
            int pos = i - k;
            while(!bst[pos].empty() && bst[pos].back().val < val)bst[pos].pop_back();
            bst[pos].push_back(Status{i, val});
        }
    }int ans(-1);
    for(int i = N - K; i <= N; ++i)ans = max(ans, dp[i][K - (N - i)]);
    printf("%d\n", ans);
    fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);
    return 0;
}

template < typename T >
inline T read(void){
    T ret(0);
    short flag(1);
    char c = getchar();
    while(c != '-' && !isdigit(c))c = getchar();
    if(c == '-')flag = -1, c = getchar();
    while(isdigit(c)){
        ret *= 10;
        ret += int(c - '0');
        c = getchar();
    }
    ret *= flag;
    return ret;
}

UPD

update-2022_11_03 初稿

标签:LG,int,题解,最大值,队列,双端,区间,P4182,dp
From: https://www.cnblogs.com/tsawke/p/16945544.html

相关文章

  • ABC247E Max Min 题解
    ABC247EMaxMinSolution目录ABC247EMaxMinSolution更好的阅读体验戳此进入题面SolutionCodeUPD更好的阅读体验戳此进入题面给定数列$A_n$,给定$X,Y$,我们定......
  • ABC247F Cards 题解
    ABC247FCardsSolution目录ABC247FCardsSolution更好的阅读体验戳此进入题面SolutionCodeUPD更好的阅读体验戳此进入题面给定$n$张卡片,每张卡片正反面各有一个......
  • AtCoder Beginner Contest 247 题解
    AtCoderBeginnerContest247Solution目录AtCoderBeginnerContest247Solution更好的阅读体验戳此进入题面链接题面Luogu链接A-MoveRight题面SolutionCodeB-U......
  • vmware workstation SCSI磁盘格式虚拟机迁移到KVM之后无法启动的问题解决办法
    原文链接:https://blog.51cto.com/duron/2125821转换磁盘镜像格式之后导入KVM系统无法启动,但是可以进入恢复模式,可能是virtio的内核模块没有加载,把磁盘改为IDE模式后正常......
  • 题解【CF1592F2 Alice and Recoloring 2】
    CF1592F2AliceandRecoloring2解题报告。不一定更好的阅读体验。摘自我的构造题目选做例题IV。CF2800的构造就这?/cf/cf/cf(首先,操作2和操作3都是没有用......
  • 上海交通大学MBA常见问题解答
    欢迎您报考上海交通大学MBA!欢迎大家提问,我们会及时为您答疑解惑。报考上海交通大学MBA常见问题解答欢迎各位考生登陆​​www.sjtumba.org/bbs​​,在那您的问题将会得到我们......
  • P4910 题解
    前言题目传送门!更好的阅读体验?矩阵快速幂优化DP经典题。题目简述给定一个长度为\(n\)的环,每个位置可以填\(1\)或\(2\)。相邻两个不能同时填\(1\)。求方案数......
  • 新生第三次练习题解
    bs来送签到啦简单思考下就知道无论选择何种路线从左上角到右下角,通过平移后就等价于先向下走到底再向右走到底,所以只要两个循环累加下两条边的的价值就能得到答案(注意循......
  • sql题解--求出平台同时在线最多的人数
    题目-求出平台同时在线最多的人数题目需求根据用户登录明细表(user_login_detail),求出平台同时在线最多的人数。结果如下:cn7需要用到的表:用户登录明细表:us......
  • 蓝桥杯 ALGO-31算法训练 开心的金明
    时间限制:1.0s内存限制:256.0MB关键字:01背包动态规划问题描述金明今天很开心,家里购置的新房就要领钥匙了,新房里有一间他自己专用的很宽敞的房间。更让他高兴的是,......