「6月雅礼集训 2017 Day4」qyh(bzoj2687 交与并)
原题传送门: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 + , N = 1e6 + , F = 1e6;
const int mod = 1e9 + ;
const ll inf = 1e15; inline int getint() {
int x = ; char ch = getchar();
while(!isdigit(ch)) ch = getchar();
while(isdigit(ch)) {
x = (x<<) + (x<<) + ch - '';
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 = ; 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<<)
# define rs (x<<|)
int w[N << ];
inline void set() {
memset(w, , 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>>;
if(pos <= mid) edt(ls, l, mid, pos, d);
else edt(rs, mid+, 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 ;
if(l == r) return l;
int mid = l+r>>;
if(w[rs] >= R) return gs(rs, mid+, 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 = , mid = l+r>>; 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-, al, pos);
solve(mid+, r, pos, ar);
} int main() {
ll tmp; T.set();
n = getint();
for (int i=; i<=n; ++i) p[i].l = getint(), p[i].r = getint();
sort(p+, p+n+);
t[tn = ] = p[]; T.edt(, , F, p[].r - p[].l, p[].r);
int mxr = p[].r;
for (int i=; i<=n; ++i) {
if(p[i].r <= mxr) {
tmp = T.gs(, , F, p[i].r);
tmp = tmp * (p[i].r - p[i].l);
if(tmp > ans) ans = tmp;
continue;
}
t[++tn] = p[i];
T.edt(, , F, p[i].r-p[i].l, p[i].r);
mxr = p[i].r;
} n = tn;
for (int i=; i<=n; ++i) p[i] = t[i]; solve(, n, , n); cout << ans << endl; return ;
}
/*
5
0 100
10 105
20 112
25 115
30 140
*/
下面那份是考场写的,过了但是有问题,可以被卡掉(感谢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 + , N = 1e6 + , F = 1e6;
const int mod = 1e9 + ; inline int getint() {
int x = ; char ch = getchar();
while(!isdigit(ch)) ch = getchar();
while(isdigit(ch)) {
x = (x<<) + (x<<) + ch - '';
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 = ; 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<<)
# define rs (x<<|)
int w[N << ];
inline void set() {
memset(w, , 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>>;
if(pos <= mid) edt(ls, l, mid, pos, d);
else edt(rs, mid+, 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 ;
if(l == r) return l;
int mid = l+r>>;
if(w[rs] >= R) return gs(rs, mid+, 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 = , 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=; i<=n; ++i) p[i].l = getint(), p[i].r = getint();
sort(p+, p+n+);
t[tn = ] = p[]; T.edt(, , F, p[].r - p[].l, p[].r);
int mxr = p[].r;
for (int i=; i<=n; ++i) {
if(p[i].r <= mxr) {
tmp = T.gs(, , F, p[i].r);
tmp = tmp * (p[i].r - p[i].l);
if(tmp > ans) ans = tmp;
continue;
}
t[++tn] = p[i];
T.edt(, , F, p[i].r-p[i].l, p[i].r);
mxr = p[i].r;
} n = tn;
for (int i=; 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 = , head = , tail = ;
for (int i=; 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 max
if (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_k
r_i * (r_j - r_k) + l_i * (l_j - l_k) > l_j * r_j - l_k * r_k suppose j>k and j is better than k
if 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 suppose j<k and j is better than k
if 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+])) ++head;
while(head <= tail && gsum(i, i-) >= gsum(i, q[tail])) --tail;
q[++tail] = i-;
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 ;
}
网上还有某种双指针做法,已经被cha掉了
4
1 301000
300990 301001
300991 301002
300992 500000
答案:3999992
「6月雅礼集训 2017 Day4」qyh(bzoj2687 交与并)的更多相关文章
- 「6月雅礼集训 2017 Day4」寻找天哥
[题目大意] 给出$n$个三维向量,设当前向量长度为$L$,每次沿着向量等概率走$[0,L]$个长度.一个球每秒半径增加1个长度,直到覆盖位置,每秒耗能为球体积,求总耗能的期望. 设最后半径为R,那么 ...
- 「6月雅礼集训 2017 Day4」暴力大神hxx
[题目大意] 给出一个n重循环,每重循环有范围$[l, r]$,其中$l$,$r$可能是之前的变量,也可能是常数.求循环最底层被执行了多少次. 其中,保证每个循环的$l$,$r$最多有一个是之前的变量 ...
- 「6月雅礼集训 2017 Day10」quote
[题目大意] 一个合法的引号序列是空串:如果引号序列合法,那么在两边加上同一个引号也合法:或是把两个合法的引号序列拼起来也是合法的. 求长度为$n$,字符集大小为$k$的合法引号序列的个数.多组数据. ...
- 「6月雅礼集训 2017 Day11」delight
[题目大意] 有$n$天,每天能吃饭.睡觉.什么事也不干 每天吃饭的愉悦值为$e_i$,睡觉的愉悦值为$s_i$,什么都不干愉悦值为0. 要求每连续$k$天都要有至少$E$天吃饭,$S$天睡觉. 求最 ...
- 「6月雅礼集训 2017 Day11」jump
[题目大意] 有$n$个位置,每个位置有一个数$x_i$,代表从$i$经过1步可以到达的点在$[\max(1, i-x_i), \min(i+x_i, n)]$中. 定义$(i,j)$的距离表示从$i ...
- 「6月雅礼集训 2017 Day11」tree
[题目大意] 给出一棵带权树,有两类点,一类黑点,一类白点. 求切断黑点和白点间路径的最小代价. $n \leq 10^5$ [题解] 直接最小割能过..但是树形dp明显更好写 设$f_{x,0/1/ ...
- 「6月雅礼集训 2017 Day10」perm(CodeForces 698F)
[题目大意] 给出一个$n$个数的序列$\{a_n\}$,其中有些地方的数为0,要求你把这个序列填成一个1到$n$的排列,使得: $(a_i, a_j) = 1$,当且仅当$(i, j) = 1$.多 ...
- 「6月雅礼集训 2017 Day8」route
[题目大意] 给出平面上$n$个点,求一条连接$n$个点的不相交的路径,使得转换的方向符合所给长度为$n-2$的字符串. $n \leq 5000$ [题解] 考虑取凸包上一点,然后如果下一个是‘R' ...
- 「6月雅礼集训 2017 Day8」gcd
[题目大意] 定义times(a, b)表示用辗转相除计算a和b的最大公约数所需步骤. 那么有: 1. times(a, b) = times(b, a) 2. times(a, 0) = 0 3. ...
随机推荐
- c# 调取 c++ dll____c#调用dll
1.以海康摄像头dll为例.(文章转载https://www.cnblogs.com/smartsensor/p/4343744.html) 海康SDK编程指南 目前使用的海康SDK包括IPC_SDK ...
- Java容器之List接口
List 接口: 1. List 接口是 Collection 的子接口,实现 List 接口的容器类中的元素是有顺序的,而且可以重复: 2. List 容器中的元素都对应一个整数型的序号记载其在容器 ...
- (三)java字符串
不可变字符串 Java没有字符串类型,而是提供了一个预定义类String. java中的字符串是不可变字符串,因此无法更改某一个字符串变量的内容. 优点:编译器可以让字符串共享.当复制一个字符串时,原 ...
- iOS- AVSpeechSynthesizer——iOS7语音合成器
语音合成器的技术是iOS7推出的,可以实现无网络语音功能,支持多种语言 1. 定义一个成员变量,记录语音合成器 AVSpeechSynthesizer #import <AVFoundation ...
- Xcode常见警告和错误
Xcode 升级后,常常遇到的遇到的警告.错误,解决方法 从sdk3.2.5升级到sdk 7.1中间废弃了很多的方法,还有一些逻辑关系更加严谨了.1,警告:“xoxoxoxo” is depreca ...
- Jekyll 使用 Rouge 主题
今日发现我的 Github Pages 中的代码并没有高亮,看了一下代码发现,原来的没有设置 css 样式的原因,我使用的代码高亮器是 rouge highlighter: rouge Rouge 是 ...
- Matlab 函数ndims简介,flipdim简介
ndims是matlab中求一个数组维数的函数. 调用格式: n=ndims(A) 将A的维数返回给变量n.n>=2 n=ndims(A)与n=length(size(A))是等价的 MATLA ...
- Atom Editor 插件 atom-less 的使用方法
一.下载安装 atom-less atom-less 项目在这里:https://github.com/schmuli/atom-less 安装方法请参考这篇博文:http://blog.csdn.n ...
- HDOJ.1075 What Are You Talking About(map)
What Are You Talking About 点我跳转到题面 点我一起学习STL-MAP 题意分析 首先第一组START-END给出翻译的字典,第二组START-END给出一句话,查找里面出现 ...
- 【Codeforces 506E】Mr.Kitayuta’s Gift&&【BZOJ 4214】黄昏下的礼物 dp转有限状态自动机+矩阵乘法优化
神题……胡乱讲述一下思维过程……首先,读懂题.然后,转化问题为构造一个长度为|T|+n的字符串,使其内含有T这个子序列.之后,想到一个简单的dp.由于是回文串,我们就增量构造半个回文串,设f(i,j, ...