zoukankan      html  css  js  c++  java
  • BZOJ2687 交与并/BZOJ2369 区间【决策单调性优化DP】【分治】

    Description

    对于一个区间集合
    {A1,A2……Ak}(K>1,Ai不等于Aj(i不等于J),定义其权值
    S=|A1∪A2∪……AK|*|A1∩A2……∩Ak|
    即它们的交区间的长度乘上它们并区间的长度。
    显然,如果这些区间没有交集则权值为0。

    Your Task

    给定你若干互不相等的区间,选出若干区间使其权值最大。

    Input

    第一行n表示区间的个数
    接下来n行每行两个整数l r描述一个区间[l,r]

    Output

    在一行中输出最大权值

    Sample Input

    4
    1 6
    4 8
    2 7
    3 5

    Sample Output

    24

    HINT

    样例解释
    选择[1,6]和[2,7]是最优的。
    数据约定
    100%:1<N<=106,1<=L<R<=106


    思路

    首先发现一个性质:更新答案的时候只会选择两个区间

    因为如果有三个区间,要么交集是空,要么有一个被包含,就很不优秀,所以最多选两个
    然后再按照左端点为第一关键字,右端点是第二关键字来排序
    扫一遍判断包含的情况
    并把不互相包含的最大区间选出来
    这个时候推一下打个表发现对于任意的(i<j<k<l),如果在k的时候j比i优,那么在l的时候j一定比i优
    也就是具有了决策单调性
    所以就可以进行分治了
    然后只需要枚举mid的决策点是哪一个递归进行就行了
    注意要特判mid没有决策点的情况,左右区间继承父亲区间的全部决策区间


    //Author: dream_maker
    #include<bits/stdc++.h>
    using namespace std;
    //----------------------------------------------
    //typename
    typedef long long ll;
    //convenient for
    #define for_up(a, b, c) for (int a = b; a <= c; ++a)
    #define for_down(a, b, c) for (int a = b; a >= c; --a)
    #define for_vector(a, b) for (int a = 0; a < (signed)b.size(); ++a)
    //inf of different typename
    const int INF_of_int = 1e9;
    const ll INF_of_ll = 1e18;
    //fast read and write
    template <typename T>
    void Read(T &x) {
      bool w = 1;x = 0;
      char c = getchar();
      while (!isdigit(c) && c != '-') c = getchar();
      if (c == '-') w = 0, c = getchar();
      while (isdigit(c)) {
        x = (x<<1) + (x<<3) + c -'0';
        c = getchar();
      }
      if (!w) x = -x;
    }
    template <typename T>
    void Write(T x) {
      if (x < 0) {
        putchar('-');
        x = -x; 
      }
      if (x > 9) Write(x / 10);
      putchar(x % 10 + '0');
    }
    //----------------------------------------------
    const int N = 1e6 + 10;
    struct Segment{
      int l, r;
    }a[N], s[N];
    int n;
    bool cmp(Segment a, Segment b) {
      if (a.l == b.l) return a.r > b.r;
      return a.l < b.l;
    }
    ll ans = 0;
    void solve(int l, int r, int pl, int pr) {
      if (l >= r) return;
      int mid = (l + r) >> 1;
      int pos = 0;ll maxv = -1;
      for_up(i, pl, min(mid - 1, pr)) {
        if (s[i].r < s[mid].l) continue;
        ll val = 1ll * (s[mid].r - s[i].l) * (s[i].r - s[mid].l);
        if (val > maxv) maxv = val, pos = i;
      }
      ans = max(ans, maxv);
      if (pos) {
        solve(l, mid, pl, pos);
        solve(mid + 1, r, pos, pr);
      } else {
        solve(l, mid, pl, pr);
        solve(mid + 1, r, pl, pr);
      }
    }
    int main() {
      Read(n);
      for_up(i, 1, n) Read(a[i].l), Read(a[i].r);
      sort(a + 1, a + n + 1, cmp);
      int tot = 0, maxr = -1, pos = 0;
      for_up(i, 1, n) {
        if (a[i].r > maxr) {
          s[++tot] = a[i];
          maxr = a[i].r;
          pos = i;
        } else {
          ans = max(ans, 1ll * (a[i].r - a[i].l) * (a[pos].r - a[pos].l));
        } 
      }
      n = tot;
      solve(1, n, 1, n);
      Write(ans);
      return 0;
    }
    
  • 相关阅读:
    基础总结深入:数据类型的分类和判断(数据、内存、变量) 对象 函数 回调函数 IIFE 函数中的this 分号
    BOM 定时器 通过修改元素的类来改变css JSON
    事件 事件的冒泡 事件的委派 事件的绑定 事件的传播
    DOM修改 使用DOM操作CSS
    包装类 Date Math 字符串的相关的方法 正则表达式 DOM DOM查询
    数组 call()、apply()、bind()的使用 this arguments
    autocad 二次开发 最小包围圆算法
    win10 objectarx向导在 vs2015中不起作用的解决办法
    AutoCad 二次开发 jig操作之标注跟随线移动
    AutoCad 二次开发 文字镜像
  • 原文地址:https://www.cnblogs.com/dream-maker-yk/p/9733828.html
Copyright © 2011-2022 走看看