CF573E Bear and Bowling 贪心、分块、凸包
传送门
题解搬运工++
先证明一个贪心做法的正确性:做以下操作若干次,每一次考虑选择没有被选到答案序列中的数加入到答案序列中对答案的贡献,设第\(i\)个位置的贡献为\(V_i\),如果最大的贡献小于0则退出,否则选择其中贡献最大的加入答案序列中。
首先一个引理:在上述贪心策略下,如果\(a_i\)>\(a_j\)且\(i\)<\(j\),则选\(i\)之前不可能选\(j\)。
证明考虑归纳:\(i,j\)中间不存在被选中的元素时是平凡的,如果\(i,j\)中间存在\(p\)个选中的元素,若\(V_i\)<\(V_j\)则一定在\([i,j]\)之间存在至少一个\(x\)满足\(a_x\)<\(a_j\),此时没有选\(j\)所以不可能选择\(x\),与假设不符,QED。
接下来假设贪心策略不正确,即在选择了集合\(A\)之后将下标为\(x\)的位置选中,但是最优的答案是选择集合\(A+B\),其中\(x \not\in B\)。那么考虑:
1、如果\(B\)中存在位置在x左边,考虑在\(x\)左边的最右位置\(y\),那么此时有\(a_y \leq a_x , V_x \geq V_y\)。此时加入集合\(B\)中的其他元素考虑\(V_x,V_y\)的变化,那么在\(x\)右边的元素对\(V_x,V_y\)的贡献一样,在\(y\)左边的元素对\(V_x,V_y\)的贡献是\(a_x,a_y\),而\(x,y\)中间没有在\(B\)中的元素,所以可以发现在其他元素加入之后\(V_x \geq V_y\),所以将\(B\)中\(y\)换成\(x\)结果不劣。
2、如果\(B\)中只有在\(x\)右边的元素,考虑在\(x\)右边的最左位置\(y\),那么\(B\)集合其他的元素对\(V_x,V_y\)的贡献是一样的,所以把\(y\)换成\(x\)也不会更劣。
故上述假设不成立,贪心正确性证毕。
那么我们考虑选择了一个元素之后对答案的影响。假如选择了位置\(x\),那么当\(y < x\)时,\(V_y += x\);当\(y > x\)时,\(V_y += a_y\)。那么每一个时刻\(V_y\)都可以表示成\(ka_y+b\)的形式,用分块维护凸包即可。
#include<cstdio>
#include<cstring>
#include<iomanip>
#include<cmath>
#include<algorithm>
#include<vector>
#include<map>
#include<set>
#include<queue>
#include<bitset>
#include<random>
#include<unistd.h>
//This code is written by Itst
using namespace std;#define int long long
#define PII pair < int , int >
#define ld long double
const int _ = 1e5 + 7 , T = sqrt(_) + 5;
int arr[_] , add[_] , mrk[T] , id[_] , N;ld sect(PII p , PII q){return 1.0 * (q.second - p.second) / (p.first - q.first);}
int calc(PII p , int q){return p.first * q + p.second;}struct Hull{deque < PII > q; int mrk;int get(){while(q.size() >= 2 && calc(q[0] , mrk) <= calc(q[1] , mrk)) q.pop_front(); return calc(q[0] , mrk);}void up(){++mrk;}void rebuild(int bl){q.clear(); mrk = 0;for(int i = bl * T ; i < N && i < (bl + 1) * T ; ++i){PII now(arr[id[i]] , add[id[i]]);if(q.size() && q.back().first == now.first)if(q.back().second > now.second) continue;else q.pop_back();while(q.size() >= 2 && sect(q[q.size() - 2] , now) < sect(q[q.size() - 2] , q[q.size() - 1])) q.pop_back();q.push_back(now);}}
}now[T];void down(int bl){for(int i = T * bl ; i < N && i < (bl + 1) * T ; ++i)add[i] += now[bl].mrk * arr[i] + mrk[bl];mrk[bl] = 0;
}signed main(){scanf("%lld" , &N);for(int i = 0 ; i < N ; ++i){scanf("%lld" , &arr[id[i] = i]); add[i] = arr[i];}for(int i = 0 ; i < N ; i += T){sort(id + i , id + min(T + i , N) , [&](int p , int q){return arr[p] < arr[q];});now[i / T].rebuild(i / T);}int sum = 0;while(1){int mx = -1e18 , id = -1;for(int i = 0 ; i < N / T + (bool)(N % T) ; ++i) if(mx < now[i].get() + mrk[i]){mx = now[i].get() + mrk[i]; id = i;}if(mx < 0) break;sum += mx; down(id);for(int i = T * id ; i < (id + 1) * T ; ++i)if(add[i] == mx){for(int j = 0 ; j < id ; ++j) mrk[j] += arr[i];for(int j = id + 1 ; j < N / T + (bool)(N % T) ; ++j) now[j].up();for(int j = T * id ; j < i ; ++j) add[j] += arr[i];add[i] = -1e15;for(int j = i + 1 ; j < N && j < (id + 1) * T ; ++j) add[j] += arr[j];now[id].rebuild(id);break;}}printf("%lld\n" , sum); return 0;
}
转载于:https://www.cnblogs.com/Itst/p/11604866.html
CF573E Bear and Bowling 贪心、分块、凸包相关推荐
- 【分治+斜率优化】BZOJ2149拆迁队 CF660F Bear and Bowling 4
BZOJ2149拆迁队 [题目] 原题地址 题目大意不想写. [题目分析] 斜率优化的dp是显然的,然后就是怎么维护的问题了. [解题思路] 这题显然就是一个斜率优化的dp,然后分治的时候维护一下凸壳 ...
- CF436F Banners(分块/凸包/单调队列)
CF436F Banners 首先有n个物品分别有ai和bi,然后定义价值为 c∗w+p∗(ai大于p且bi小于c的用户个数)c*w+p*(ai大于p且bi小于c的用户个数)c∗w+p∗(ai大于p且 ...
- 2016区域赛前冲刺训练
UPD 2016.10.23 shift-and (2题) Codeforces 训练 现在已经完成了: 191 [Codeforces Round #377] (6/6) Div 2 A Buy a ...
- 一句话题解(20180210~)
2.9 BZOJ 2006 [NOI2010]超级钢琴.这道题目几天之前就做了.做法是固定右端点,左端点在ST表上走,走法其实就是笛卡尔树的走法.完结撒花! BZOJ 1218 [HNOI2003]激 ...
- atcoder题目合集(持续更新中)
Choosing Points 数学 Integers on a Tree 构造 Leftmost Ball 计数dp+组合数学 Painting Graphs with AtCoDeer tarja ...
- 2018 noip 考前临死挣扎
基础算法 倍增 贪心 分块 二分 三分 数据结构 线段树 对顶堆 数学 质数 约数 同余 组合 矩阵乘法 图论 二分图判定以及最大匹配 字符串 Tire树 KMP 最小表示法 Hash Manache ...
- [CodeForces 1603C] Extreme Extension(贪心 + 数论分块优化dp)
problem CodeForces solution observation1:\text{observation1}:observation1: 对于一个非空子段 [l,r][l,r][l,r], ...
- 【CodeForces - 628C】Bear and String Distance(贪心,构造)
Description 定义两个小写字母之间的距离为这两个字母在字母表中的距离,如dis(a,z)=25,dis(a,c)=2,两个长度相同串的距离为这两个串对应位置字母距离之和.现给出一个长度为n ...
- 【牛客 - 551E】CSL 的魔法(贪心,思维,STLmap,分块)
题干: 链接:https://ac.nowcoder.com/acm/contest/551/E 来源:牛客网 有两个长度为 n 的序列,a0,a1,-,an−1a0,a1,-,an−1和 b0,b1 ...
- 【分块】[LUOGU 旅行规划] 分块+二分+凸包优化
题目: 题目链接:[LUOGU 旅行规划] 题解: (由于这个,,我竟然还去写了二维凸包的模板题作为练习,,,然而,一点用都没有,,,,) 先解释一下题面的意思:就是一个区间加的操作,再加上一个区间的 ...
最新文章
- Symfony2 学习笔记之模板使用
- 餐厅管理程序c语言源代码,课内资源 - 基于C++的餐厅管理程序的设计与实现
- CentOS 初体验五: SSH远程连接
- python删除链表中重复的节点_Java编程删除链表中重复的节点问题解决思路及源码分享...
- scala case class 继承_数字硬件系统设计之一:Scala快速入门(2)
- Spring Bean范围
- Tcp三次握手和四次挥手状态图
- Android O 获取APK文件权限 Demo案例
- oracle 11g r2版本号,Oracle 11g r2新增版本功能(二)
- 数据结构——>线索化二叉树
- 电脑f2还原系统步骤_电脑还原系统方法步骤详解
- excel向下填充公式快捷键
- CRMEB 知识付费模版消息修改教程
- 基于组件开发——应用软件开发的革命
- 分享simsimi.com小黄鸡官方免费api接口
- python 必应搜索教程
- 计算机不识别固态硬盘,win7系统电脑无法识别M.2固态硬盘如何解决
- Pytorch应用训练好的模型
- php mysql敏感词_PHP违禁词敏感词 全站文件扫描
- 5款光盘数据恢复软件帮你忙!
热门文章
- 会话技术——Cookie和Session
- java hostnameverifier_关于HostnameVerifier接口的解读
- C++ std::function怎么用
- 【Django 2021年最新版教程14】session是什么 如何使用
- thinkphp 捕捉错误
- 《我一开口,就能说服所有人》读书随记
- 在jquery中想要找到所以同辈元素方法_在jquery中siblings找到所有元素的同辈元素,是什么意思,有人可以给我详细讲解一下不?...
- 2.15.PHP7.1 狐教程-【PHP 抽象类、抽象方法】
- gitblit git SERVER window 安装配置 hook post-receive 自动部署
- ubuntu 安装mysql 5.5.28 编译安装 innodb 配置