[LOJ 6213]「美团 CodeM 决赛」radar
[LOJ 6213]「美团 CodeM 决赛」radar
题意
给定 \(n\) 个横坐标 \(x_i\) , 为它们选择一个不超过 \(y_i\) 的纵坐标 \(h_i\), 产生 \(c_ih_i\) 的花费. 选择之后产生的总价值是所有以 \((x_i,h_i)\) 到 \(x\) 轴的垂线段为斜边上的高的等腰直角三角形的并的面积. 最大化总价值与总花费之间的差并输出这个差.
\(n\le 1\times 10^5\).
题解
首先有一个比较显然的沙雕性质, 就是某个三角形的高要么是 \(0\) 要么是 \(y_i\). 因为假设已经选择了一些三角形, 要求选择这个点之后对最后答案的贡献, 必然是一个下凸的二次函数. 显然这样的函数的区间最大值只能取在端点.
其次有另一个显然但是容易被忽略的性质, 就是最优解中不存在一个三角形被另一个三角形完全包含. 也就是说当计算选中一个新的三角形的贡献的时候不可能会出现一些鬼畜边界线的情况考试时成功忽略这个性质于是没敢写
因为不可能被完全包含, 所以我们可以按照三角形在 \(x\) 轴上覆盖的右端点升序排序, 定义 \(dp_i\) 表示前 \(i\) 个三角形中选中最后一个三角形时能产生的最大答案. 因为不难发现唯一需要出现的浮点数是 \(\frac 1 4\), 于是我们计算答案的 \(4\) 倍, 这样就有三种转移情况.
定义 \(l_i,r_i\) 分别为三角形在 \(x\) 轴上覆盖的左右端点, \(w_i\) 为 \(4(y_i^2-c_iy_i)\) :
\begin{cases}
dp_j+w_i &(r_j<l_i)\\
dp_j-(r_j-l_i)^2+w_i &(r_j\ge l_i)
\end{cases}
\]
其中第一种转移显然是个前缀 \(\max\), 因为已经按 \(r_i\) 排过序了所以直接二分找到最后一个做这种贡献的位置然后取前缀 \(\max\) 就可以了.
第二种转移需要拆一拆...
dp_i&=\max_{j<i,r_j\ge l_i} \{dp_j-(r_j-l_i)^2+w_i\}\\
&=\max_{j<i,r_j\ge l_i}\{dp_j-r_j^2+2r_jl_i-l_i^2+w_i\}\\
&=\max_{j<i,r_j\ge l_i}\{dp_j-r_j^2+2r_jl_i\}-l_i^2+w_i
\end{aligned}
\]
其中 \(\max\) 里面是一个一次函数的形式, 可以用李超树来搞.
等一下!
李超树怎么处理 \(r_j\ge l_i\) 这个限制呢? 换句话说, 我们怎么在计算第二部分贡献的时候排除 \(r_j<l_i\) 的点的贡献呢?
其实不用排除因为如果某个点同时做贡献的话第二种贡献是要小于第一种的233
于是直接李超树上就可以了. 总时间复杂度 \(O(n\log n)\).
参考代码
#include <bits/stdc++.h>
const int MAXN=1e5+10;
typedef long long intEx;
struct Point{
int l;
int r;
intEx w;
};
Point P[MAXN];
int n;
int s[MAXN];
intEx smax[MAXN];
struct Line{
intEx k;
intEx b;
Line(const intEx& a,const intEx& b):k(a),b(b){}
inline intEx operator()(const int& x)const{
return k*s[x]+b;
}
};
struct Node{
int l;
int r;
Line f;
Node* lch;
Node* rch;
~Node();
Node(int,int);
intEx Query(int);
void Insert(Line);
};
int main(){
freopen("radar.in","r",stdin);
freopen("radar.out","w",stdout);
int T;
scanf("%d",&T);
while(T--){
scanf("%d",&n);
for(int i=1;i<=n;i++){
int x,y,c;
scanf("%d%d%d",&x,&y,&c);
P[i].l=x-y;
P[i].r=x+y;
s[i]=P[i].l;
P[i].w=4ll*y*y-4ll*c*y;
}
std::sort(P+1,P+n+1,
[](const Point& a,const Point& b){
return a.r<b.r;
}
);
std::sort(s+1,s+n+1);
int cnt=std::unique(s+1,s+n+1)-s-1;
Node* N=new Node(1,cnt);
for(int i=1;i<=n;i++){
// printf("[%d,%d] w=%lld\n",P[i].l,P[i].r,P[i].w);
int h=std::lower_bound(s+1,s+cnt+1,P[i].l)-s;
intEx dp=N->Query(h)-1ll*P[i].l*P[i].l+P[i].w;
int p=std::lower_bound(P+1,P+n+1,P[i].l,
[](const Point& a,const int& b){
return a.r<b;
}
)-P-1;
dp=std::max(smax[p]+P[i].w,dp);
N->Insert(Line(2*P[i].r,dp-1ll*P[i].r*P[i].r));
smax[i]=std::max(smax[i-1],dp);
}
printf("%lld.%02lld\n",smax[n]>>2,(smax[n]&3)*25);
delete N;
}
return 0;
}
intEx Node::Query(int x){
if(this->l==this->r)
return this->f(x);
else{
if(x<=this->lch->r)
return std::max(this->lch->Query(x),this->f(x));
else
return std::max(this->rch->Query(x),this->f(x));
}
}
void Node::Insert(Line f){
int mid=(this->l+this->r)>>1;
if(f(mid)>this->f(mid))
std::swap(f,this->f);
intEx ld=this->f(this->l)-f(this->l);
intEx rd=this->f(this->r)-f(this->r);
if(ld>=0&&rd>=0)
return;
else if(rd>=0)
this->lch->Insert(f);
else
this->rch->Insert(f);
}
Node::~Node(){
if(this->lch)
delete this->lch;
if(this->rch)
delete this->rch;
}
Node::Node(int l,int r):l(l),r(r),f(0,-1e18),lch(NULL),rch(NULL){
if(l!=r){
int mid=(l+r)>>1;
this->lch=new Node(l,mid);
this->rch=new Node(mid+1,r);
}
}

[LOJ 6213]「美团 CodeM 决赛」radar的更多相关文章
- LibreOJ #6212. 「美团 CodeM 决赛」melon
二次联通门 : LibreOJ #6212. 「美团 CodeM 决赛」melon /* LibreOJ #6212. 「美团 CodeM 决赛」melon MDZZ 这是决赛题?? */ #incl ...
- LOJ #6192. 「美团 CodeM 复赛」城市网络 (树上倍增)
#6192. 「美团 CodeM 复赛」城市网络 内存限制:64 MiB 时间限制:500 ms 标准输入输出 题目描述 有一个树状的城市网络(即 nnn 个城市由 n−1n-1n−1 条道路连接 ...
- LOJ#6085. 「美团 CodeM 资格赛」优惠券(set)
题意 题目链接 Sol 考虑不合法的情况只有两种: 进去了 再次进去 没进去 但是出来了 显然可以用未知记录抵消掉 直接开个set维护一下所有未知记录的位置 最优策略一定是最后一次操作位置的后继 同时 ...
- loj 6085.「美团 CodeM 资格赛」优惠券
题目: 一个有门禁的大楼,初始时里面没有人. 现在有一些人在进出大楼,每个人都有一个唯一的编号.现在有他们进出大楼的记录,但是有些被污染了,只能知道这里有一条记录,具体并不能知道. 一个人只有进大楼, ...
- loj 6084.「美团 CodeM 资格赛」跳格子
题目: link 题解: 尽量走\(a\). 只要保证走\(a\)后到达的点一定可以到终点就可以走. 所以从终点开始\(dfs\)出所有能够到达终点的点. 然后再从起点开始\(dfs\)路径即可. 如 ...
- loj 6083.「美团 CodeM 资格赛」数码
题目: 给定两个整数\(l\)和\(r\),对于任意\(x\),满足\(l\leq x\leq r\),把\(x\)所有约数写下来. 对于每个写下来的数,只保留最高位的那个数码.求\([1,9]\)中 ...
- LiberOJ #6210. 「美团 CodeM 决赛」tree 树形DP
题目链接:点这里 题解: 需要证明,所求的路径一定是全部权值都为1或者,路径上权值至多有一个为2其余为1且权值2在路径中央. 然后树形DP 设定dp[i][0/1] 以1为根的情况下,以i 节点下子树 ...
- loj #6191. 「美团 CodeM 复赛」配对游戏 期望dp
题意:有一个栈,随机插入 $n$ 次 $0$/$1$ 如果栈顶是 $1$,然后插入 $0$,则将这两个元素都弹出,否则,插入栈顶. 求:$n$ 次操作后栈中期望的元素个数. 我们发现,按照上述弹栈方式 ...
- LibreOJ #6192. 「美团 CodeM 复赛」城市网络
#6192. 「美团 CodeM 复赛」城市网络 内存限制:64 MiB时间限制:500 ms标准输入输出 题目类型:传统评测方式:文本比较 上传者: sqc 提交提交记录统计讨论测试数据 题目描 ...
随机推荐
- Python程序中的进程操作-进程间数据共享(multiprocess.Manager)
目录 一.进程之间的数据共享 1.1 Manager模块介绍 1.2 Manager例子 一.进程之间的数据共享 展望未来,基于消息传递的并发编程是大势所趋 即便是使用线程,推荐做法也是将程序设计为大 ...
- flask--数据库迁移之连环踩坑记
flask数据库迁移命令: python manage.py db init python manage.py db migrate python manage.py db upgrade 1.报错: ...
- LeetCode | 机器人能否返回原点
放假的时间已经过去一半了,每天坚持看一个多小时的书,时间虽然不多,但是能专心把书看进去就可以了.今天分享的是 LeetCode 上面的第 657 题,题目是<机器人能否返回原点>,这也是一 ...
- 细数使用View UI(iView)开发中遇到的坑
一.前言 View UI,即原先的 iView,是一套基于 Vue.js 的开源 UI 组件库,主要服务于 PC 界面的中后台产品. 官网地址:https://www.iviewui.com/docs ...
- 导出HTML5 Canvas图片并上传服务器功能
这篇文章主要介绍了导出HTML5 Canvas图片并上传服务器功能,文中通过实例代码给大家介绍了HTML5 Canvas转化成图片后上传服务器,代码简单易懂非常不错,具有一定的参考借鉴价值,需要的朋友 ...
- C++ 名字重载、隐藏、覆盖
名字重载Name overloading 如果顶层函数有不同的签名,则函数名可以相同. 如果同一类中的函数有不同的签名,则函数名可以相同. C++中允许在相同的作用域内以相同的名字定义几个不同实现 ...
- 列举常见国内外做服务器与存储的IT厂家
列举常见国内外做服务器与存储的IT厂家 联想.浪潮.曙光.同有飞骥.迪菲特.宝德.星盈.元谷.威联通.群晖.忆捷.天敏等 华为.华三.戴尔.神州云科.同有.谷数,都是比较大的厂商 HDS(昆仑联通). ...
- python基础(32):进程(二)
1. multiprocess模块 仔细说来,multiprocess不是一个模块而是python中一个操作.管理进程的包. 之所以叫multi是取自multiple的多功能的意思,在这个包中几乎包含 ...
- python基础(8):基本数据类型三(dict)、is和==、编码和解码
1. 字典 1.1 字典的介绍 字典(dict)是python中唯一的一个映射数据类型,它是以{}括起来的键值对组成.在dict中key是唯一的,在保存的时候,根据key来计算出一个内存地址,然后将k ...
- MySQL学习——存储引擎
MySQL学习——存储引擎 摘要:本文主要学习了MySQL数据库的存储引擎. 什么是存储引擎 数据库存储引擎是数据库底层软件组件,数据库管理系统使用数据引擎进行创建.查询.更新和删除数据操作.不同的存 ...