原题传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=2687

【题目大意】

给出若干区间,求一个区间的大于等于2的子集,使得 |区间并| 和 |区间交| 的乘积最大。

$1\leq n,L_i,R_i\leq 10^6$

【题解】

把区间去掉包含情况,然后进行排序,变成$l_i$和$r_i$都递增的数列。

然后容易发现取得区间一定是连续的一段。

然后我们推一推决策单调性。

容易得出当$j$优于$k$的情况:

$r_i * (r_j - r_k) + l_i * (l_j - l_k) > l_j * r_j - l_k * r_k$

当$i$变化成$i+1$的时候,若$j > k$,那么如下情况还成立。

说明当$i$往右的时候,最优决策点不会往左。

然后要注意的是,还有一种情况,也就是包含的情况需要讨论。

我的做法可能比较奇怪,包含的情况,对于每个被包含的区间,贡献最大值是包含它的长度最长的区间。

我们对左端点进行排序,发现要找的包含的一定是右端点大于当前讨论区间的右端点(左端点已经固定小于了),的最长区间。

我们对于区间长度建一棵线段树,然后线段树维护长度在区间内的右端点max,询问相当于在线段树上二分,复杂度$O(logn)$。

现在来讨论有了决策单调性要怎么办

1. 维护一个i递增,答案递减的的单调队列。

2. 二分决策

考虑第一种方案,当$i$右移的时候,前面一个单调下降函数,不一定会变成一个单峰或单调下降的函数,可能是有很多峰值,我们当前爬
上的这个峰不是最优解。

网上基本上所有单调队列代码都是错的(我只看到一份对的),包括我之前发的那份文章也是错的。可以被这个数据卡掉:

5
0 100
10 105
20 112
25 115
30 140

最优解是选择[20,112], [25,115], [30,140](中间的那个区间可以选可以不选)。

可是由于我们的单调队列的设定,左端点会一直停留在[0,100]这个区间,实际上后面的[20,112]这个区间比[0,100]更优。

所以只能二分决策了。。

二分的时候有个技巧,就是可以按照类似于整体二分的思路。

定义solve(l, r, al, ar)

表示目前处理[l,r]之间的转移,决策点在[al, ar]之间。

然后每次暴力找出mid的时候的决策即可。

# include <queue>
# include <stdio.h>
# include <string.h>
# include <iostream>
# include <algorithm>using namespace std;typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;const int M = 2e5 + 10, N = 1e6 + 10, F = 1e6;
const int mod = 1e9 + 7;
const ll inf = 1e15;inline int getint() {int x = 0; char ch = getchar();while(!isdigit(ch)) ch = getchar();while(isdigit(ch)) {x = (x<<3) + (x<<1) + ch - '0';ch = getchar();}return x;
}int n, q[N];
ll ans;
struct pa {int l, r;pa() {}pa(int l, int r) : l(l), r(r) {}friend bool operator < (pa a, pa b) {return a.l < b.l || (a.l == b.l && a.r > b.r);}
}p[N], t[N]; int tn = 0;inline bool cmp(pa a, pa b) {return a.l < b.l || (a.l == b.l && a.r < b.r);
} inline ll gsum(int i, int j) {return (ll)(p[i].r-p[j].l) * (ll)(p[j].r-p[i].l);
}int RM[N];struct SMT { # define ls (x<<1)# define rs (x<<1|1)int w[N << 2];inline void set() {memset(w, 0, sizeof w);}inline void edt(int x, int l, int r, int pos, int d) {if(l == r) {w[x] = max(w[x], d);return ;}int mid = l+r>>1;if(pos <= mid) edt(ls, l, mid, pos, d);else edt(rs, mid+1, r, pos, d);w[x] = max(w[ls], w[rs]);}inline int gs(int x, int l, int r, int R) {if(w[x] < R) return 0;if(l == r) return l;int mid = l+r>>1;if(w[rs] >= R) return gs(rs, mid+1, r, R);else return gs(ls, l, mid, R);}
}T;inline void solve(int l, int r, int al, int ar) {if(l > r) return ;int pos = 0, mid = l+r>>1; ll mx = -1e15, t;for (int i=al; i<=ar && i<mid; ++i) if((t = gsum(mid, i)) > mx) mx = t, pos = i;if(pos) ans = max(ans, gsum(mid, pos));solve(l, mid-1, al, pos);solve(mid+1, r, pos, ar);
}int main() {ll tmp; T.set();n = getint();for (int i=1; i<=n; ++i) p[i].l = getint(), p[i].r = getint();sort(p+1, p+n+1);t[tn = 1] = p[1]; T.edt(1, 0, F, p[1].r - p[1].l, p[1].r);int mxr = p[1].r;for (int i=2; i<=n; ++i) {if(p[i].r <= mxr) {tmp = T.gs(1, 0, F, p[i].r);tmp = tmp * (p[i].r - p[i].l);if(tmp > ans) ans = tmp;continue;}t[++tn] = p[i]; T.edt(1, 0, F, p[i].r-p[i].l, p[i].r);mxr = p[i].r;}n = tn;for (int i=1; i<=n; ++i) p[i] = t[i];solve(1, n, 1, n);cout << ans << endl;return 0;
}
/*
5
0 100
10 105
20 112
25 115
30 140
*/

View Code

下面那份是考场写的,过了但是有问题,可以被卡掉(感谢chrt给我了一个提醒,发现自己代码是错的qwq)

# include <queue>
# include <stdio.h>
# include <string.h>
# include <iostream>
# include <algorithm>using namespace std;typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;const int M = 2e5 + 10, N = 1e6 + 10, F = 1e6;
const int mod = 1e9 + 7;inline int getint() {int x = 0; char ch = getchar();while(!isdigit(ch)) ch = getchar();while(isdigit(ch)) {x = (x<<3) + (x<<1) + ch - '0';ch = getchar();}return x;
}int n, q[N];
struct pa {int l, r;pa() {}pa(int l, int r) : l(l), r(r) {}friend bool operator < (pa a, pa b) {return a.l < b.l || (a.l == b.l && a.r > b.r);}
}p[N], t[N]; int tn = 0;inline bool cmp(pa a, pa b) {return a.l < b.l || (a.l == b.l && a.r < b.r);
} /*
inline int gs(int x) {int l = 1, r = n, mid;while(1) {if(r-l <= 3) {for (int i=l; i<=r; ++i) if(p[i].r > x) return i;return -1;}mid = l+r>>1;if(p[mid].r > x) r = mid;else l = mid;}return -1;
}
*/inline ll gsum(int i, int j) {return (ll)(p[i].r-p[j].l) * (ll)(p[j].r-p[i].l);
}int RM[N];struct SMT { # define ls (x<<1)# define rs (x<<1|1)int w[N << 2];inline void set() {memset(w, 0, sizeof w);}inline void edt(int x, int l, int r, int pos, int d) {if(l == r) {w[x] = max(w[x], d);return ;}int mid = l+r>>1;if(pos <= mid) edt(ls, l, mid, pos, d);else edt(rs, mid+1, r, pos, d);w[x] = max(w[ls], w[rs]);}inline int gs(int x, int l, int r, int R) {if(w[x] < R) return 0;if(l == r) return l;int mid = l+r>>1;if(w[rs] >= R) return gs(rs, mid+1, r, R);else return gs(ls, l, mid, R);}
}T;// # include <time.h>int main() {
//    int tm = clock();freopen("qyh.in", "r", stdin);freopen("qyh.out", "w", stdout);ll ans = 0, tmp; T.set();
//    cin >> n; n = getint();
//    for (int i=1; i<=n; ++i) scanf("%d%d", &p[i].l, &p[i].r);for (int i=1; i<=n; ++i) p[i].l = getint(), p[i].r = getint();sort(p+1, p+n+1);t[tn = 1] = p[1]; T.edt(1, 0, F, p[1].r - p[1].l, p[1].r);int mxr = p[1].r;for (int i=2; i<=n; ++i) {if(p[i].r <= mxr) {tmp = T.gs(1, 0, F, p[i].r);tmp = tmp * (p[i].r - p[i].l);if(tmp > ans) ans = tmp;continue;}t[++tn] = p[i]; T.edt(1, 0, F, p[i].r-p[i].l, p[i].r);mxr = p[i].r;}n = tn;for (int i=1; i<=n; ++i) p[i] = t[i];
//    for (int i=1; i<=n; ++i) printf("%d %d\n", p[i].l, p[i].r);int lst = 1, head = 1, tail = 0;for (int i=2; i<=n; ++i) {/* (r_i - l_j) * (r_j - l_i)r_i * r_j + l_i * l_j - l_j * r_j - l_i * r_i   maxif   (r_i - l_j) * (r_j - l_i) > (r_i - l_k) * (r_k - l_i)r_i * r_j + l_i * l_j - l_j * r_j > r_i * r_k + l_i * l_k - l_k * r_kr_i * (r_j - r_k) + l_i * (l_j - l_k) > l_j * r_j - l_k * r_ksuppose j>k and j is better than kif i + 1, then r_{i+1} * (r_j - r_k) + l_{i+1} * (l_j - l_k) > l_j * r_j - l_k * r_ksuppose j<k and j is better than kif i + 1, then r_{i+1} * (r_j - r_k) + l_{i+1} * (l_j - l_k) > l_j * r_j - l_k * r_k*//*if(gsum(i, i-1) > gsum(i, lst)) lst = i-1;tmp = gsum(i, lst);
//        cout << lst << endl;if(tmp > ans) ans = tmp;*/while(head < tail && gsum(i, q[head]) < gsum(i, q[head+1])) ++head;while(head <= tail && gsum(i, i-1) >= gsum(i, q[tail])) --tail;q[++tail] = i-1;if(head <= tail) {
//            printf("%d %d\n", i, q[head]);tmp = gsum(i, q[head]);if(tmp > ans) ans = tmp;}}cout << ans;//    cerr << clock() - tm << " ms" << endl;return 0;
}

View Code

网上还有某种双指针做法,已经被cha掉了

4
1 301000
300990 301001
300991 301002
300992 500000

答案:3999992

转载于:https://www.cnblogs.com/galaxies/p/20170620_b.html

「6月雅礼集训 2017 Day4」qyh(bzoj2687 交与并)相关推荐

  1. 「6月雅礼集训 2017 Day4」暴力大神hxx

    [题目大意] 给出一个n重循环,每重循环有范围$[l, r]$,其中$l$,$r$可能是之前的变量,也可能是常数.求循环最底层被执行了多少次. 其中,保证每个循环的$l$,$r$最多有一个是之前的变量 ...

  2. 「6月雅礼集训 2017 Day7」回转寿司

    [题目大意] 给一个n个数的序列,q次操作,每次选择区间$[l,r]$,给出数p,对于区间$[l,r]$的每个数$x$,做如下操作: 如果$x > p$,就交换$x$和$p$.求每次操作后$p$ ...

  3. 「6月雅礼集训 2017 Day5」吃干饭

    [题目大意] 询问[L,R]中选若干个数异或起来得到的答案集合大小.多组数据. 对于50%的数据,$R - L \leq 10^4$ 对于100%的数据,$R - L \leq 10^{18}, T ...

  4. 「6月雅礼集训 2017 Day2」B

    [题目大意] 求n*n的棋盘,每行每列都有2个黑格子的方案数. n<=10^7 [题解] zzq的做法好神奇啊 行列建点,二分图 左边有i个点,右边有j个点的方案数 f[i,j] 左边有i个点, ...

  5. Loj 6036 「雅礼集训 2017 Day4」编码 - 2-sat

    题目传送门 唯一的传送门 题目大意 给定$n$个串,每个串只包含 '0','1','?' ,其中 '?' 至多在每个串中出现1次,它可以被替换为 '0' 或 '1' .问是否可能任意两个不同的串不满足 ...

  6. Loj #6503. 「雅礼集训 2018 Day4」Magic

    Loj #6503. 「雅礼集训 2018 Day4」Magic 题目描述 前进!前进!不择手段地前进!--托马斯 · 维德 魔法纪元元年. 1453 年 5 月 3 日 16 时,高维碎片接触地球. ...

  7. 数据结构二之线段树Ⅱ——KiKi‘s K-Number,ball,The Child and Sequence,「雅礼集训 2017 Day1」市场,Atlantis

    值域线段树+势能线段树+扫描线 KiKi's K-Number ball The Child and Sequence 「雅礼集训 2017 Day1」市场 Atlantis KiKi's K-Num ...

  8. [LOJ 6042]「雅礼集训 2017 Day7」跳蚤王国的宰相(树的重心+贪心)

    [LOJ 6042]「雅礼集训 2017 Day7」跳蚤王国的宰相 description solution 一个到所有节点距离和最小的节点 ⇔\Leftrightarrow⇔ 树的重心(满足最重的儿 ...

  9. #6029. 「雅礼集训 2017 Day1」市场(势能,区间除)

    #6029. 「雅礼集训 2017 Day1」市场 用线段树维护数列,区间上维护最大最小值,区间和还有标记,修改时,区间加直接做,而区间除时,递归到线段树上某一区间,如果这一操作等价于区间加(也就是最 ...

最新文章

  1. python自动化测试视频百度云-Python接口自动化测试 PDF 超清版
  2. leetcode239. 滑动窗口最大值(思路+详解)
  3. YbtOJ#20089-[NOIP2020模拟赛B组Day10]平衡的树【贪心】
  4. 《C++ Primer Plus》读书笔记之十—类和动态内存分配
  5. C++ const修饰指针变量的位置不同代表的意义
  6. Chrome 87 发布,获多年来最大性能提升
  7. 老外写的比较好用的splitter控件
  8. Allegro设置尺寸单位milmm
  9. oracle. 设置参数 sid,更改Oracle数据库的SID
  10. python 回溯法 01背包问题_01背包问题(回溯法)python实现
  11. Caffe2 - (二十四) Detectron 之 utils 函数(2)
  12. 仓储机器人的3位鼻祖
  13. STM32液晶显示中英文
  14. 【Python】数据可视化-散点图绘制
  15. netty整合shiro,报There is no session with id [xxxxxx]问题定位及解决
  16. python实现mnist手写数字识别
  17. 广工android嵌入式系统试卷_嵌入式系统试卷
  18. 如何破解4399上的小游戏
  19. LPDDR5 更新提高速度
  20. Niagara解决设备连接应用的软件框架平台技术。

热门文章

  1. cocos2d-x塔防游戏教程(四)
  2. Android Eclipse如何用BlueStacks模拟器
  3. Python爬虫01——第一个小爬虫
  4. html中文字阴影扁平,jQuery扁平化图标文字长阴影特效插件
  5. Autojs实现蚂蚁森林自动收取能量球
  6. hadoop启动缺少NameNode, 缺少ResourceManager, 缺少NodeManager...
  7. ADAS中的LDW、FCW、BSD、LCA、ACC、AEB、APA、DMS代表的含义
  8. 62.大数据之旅——电信日志项目05-电信日志数据处理
  9. 基于深度学习的影像深度重建综述
  10. 服务器安装信任描述文件,OS X Server:在使用 TLS、TTLS 或 PEAP 时如何在“配置描述文件”中配置 RADIUS 服务器信任...