zoukankan      html  css  js  c++  java
  • bzoj 5185 Lifeguards

    题目传送门

      传送点I

      传送点II

    题目大意

      给定$n$个区间,问恰好删去其中$k$个,剩下的区间的并的最大总长度。

      显然被包含的区间一定不优。再加上被包含的区间对计数不友好。直接把它删掉。

      注意到题目说恰好,其实是骗人的。多删几个也不会影响(删太多了就有影响了)。

      按照右端点排序,然后用$f[i][j]$表示考虑前$i$个区间,已经选了删掉$j$个。

      考虑转移,第一种情况是第$i$个区间不选,直接通过$i - 1$转移。

      第二种情况是要选$i$。然后要计算贡献。这时考虑上一个选择的是什么?

    • 如果和第$i$个区间有相交,那么显然选择左端点最小的一个和当前区间相交的线段作为上一个。然后中间的线段全部删掉(因为它们被包含了。)。答案补上这个区间覆盖不到的但当前区间能够覆盖的地方。(如果上一个不是选的这个区间也无妨,因为这样一定没有下面这样的转移优)
    • 否则从左端点最小的一个区间的前一个区间转移。答案加上当前区间长度。

    Code

     1 /**
     2  * bzoj
     3  * Problem#5185
     4  * Accepted
     5  * Time: 1140ms
     6  * Memory: 43876k
     7  */
     8 #include <bits/stdc++.h>
     9 using namespace std;
    10 typedef bool boolean;
    11 
    12 typedef class Segment {
    13     public:
    14         int l, r;
    15 
    16         boolean operator < (Segment b) const {
    17             if (r ^ b.r)    return r < b.r;
    18             return l < b.l;
    19         }
    20 }Segment;
    21 
    22 const int N = 1e5 + 5, K = 105;
    23 
    24 int n, m, k;
    25 Segment* bs;
    26 Segment* ss;
    27 int f[N][K];
    28 
    29 inline void init() {
    30     scanf("%d%d", &n, &k);
    31     bs = new Segment[(n + 1)];
    32     ss = new Segment[(n + 1)];
    33     for (int i = 1; i <= n; i++)
    34         scanf("%d%d", &bs[i].l, &bs[i].r);
    35 }
    36 
    37 inline void solve() {
    38     sort(bs + 1, bs + n + 1);
    39     for (int i = 1; i <= n; i++) {
    40         if (i == 1 || bs[i].r != bs[i - 1].r)
    41             ss[++m] = bs[i];
    42         else
    43             k--;
    44     }
    45     
    46     int mil = (signed) (~0u >> 1);
    47     n = 0;
    48     for (int i = m; i; i--) {
    49         if (ss[i].l < mil)
    50             bs[++n] = ss[i], mil = ss[i].l;
    51         else
    52             k--;
    53     }
    54     sort(bs + 1, bs + n + 1);
    55     k = max(k, 0);
    56     memset(f, 0x80, sizeof(f[0]) * (m + 1));
    57     int p = 1;
    58     f[0][0] = 0;
    59     for (int i = 1; i <= n; i++) {
    60         while (p <= i && bs[p].r < bs[i].l)
    61             p++;
    62         assert(p <= i);
    63         for (int j = 1; j <= k; j++)
    64             f[i][j] = max(f[i][j], f[i - 1][j - 1]);
    65         f[i][k] = max(f[i][k], f[i - 1][k]);
    66         
    67         for (int j = 0; j <= k; j++) {
    68             int cj = min(j + i - p - 1, k);
    69             if (p ^ i)
    70                 f[i][cj] = max(f[i][cj], f[p][j] + bs[i].r - bs[p].r);
    71             cj = min(cj + 1, k);
    72             f[i][cj] = max(f[i][cj], f[p - 1][j] + bs[i].r - bs[i].l);
    73         }
    74     }
    75     printf("%d
    ", f[n][k]);
    76 }
    77 
    78 int main() {
    79     init();
    80     solve();
    81     return 0;
    82 }
  • 相关阅读:
    面向对象高级
    Intellij IDEA 激活码 | Intellij IDEA 注册码
    如何保证核心链路稳定性的流控和熔断机制?
    消息模型:主题和队列有什么区别?
    MySQL中悲观锁和乐观锁到底是什么?
    SQL是如何在数据库中执行的?
    ZooKeeper 面试题(30道ATM精选问题)
    线上服务的FGC问题排查,看这篇就够了!
    一次线上JVM调优实践,FullGC40次/天到10天一次的优化过程
    由多线程内存溢出产生的实战分析
  • 原文地址:https://www.cnblogs.com/yyf0309/p/9451619.html
Copyright © 2011-2022 走看看