[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 提交提交记录统计讨论测试数据 题目描 ...
随机推荐
- 构建LVS负载均衡集群——NAT模式(最简单方式)
一.装备一台lvs调度器主机要求两个网卡一个为内部局域网ip,一个为公网ip #IP地址设置过程不再重复 [root@localhost ~]# ip a | grep eth0 #内网ip : et ...
- 使用rsync基于ssh免密登陆进行备份或目录同步
日常工作中有很多的备份工作,rsync是一个很不错的工具,尝试使用基于ssh免密登陆的方式进行备份,测试成功,是可行且方便的方法,撰文记之,以备后用: 1.A主机root用户对B主机root用户做ss ...
- LeetCode | 2 的幂
LeetCode 题库的第 231 题 —— 2 的幂 这题也是比较容易的一题,前提是找到规律即可.如果从 10 进制的角度观察 2 的幂次方,可能并不容易发现规律,那么可以从 2 进制的角度进行观察 ...
- 英语阅读——Love and logic:The story of a fallacy
这篇文章是<新视野大学英语>第四册的第一单元的文章,读着挺有趣,便拿过来分享一下. 1 I had my first date with Polly after I made the tr ...
- oracle里面查询重复数据的方法
一张person表,有id和name的两个字段,id是唯一的不允许重复,id相同则认为是重复的记录. select id from group by id having count(*) > 1 ...
- wpf dual monitor
<Window x:Class="DualMonitors.Views.WinLeft" xmlns="http://schemas.microsoft.com/w ...
- Python爬取知乎单个问题下的回答
前言 本文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理. 作者: 努力学习的渣渣哦 PS:如有需要Python学习资料的小伙伴可以加 ...
- 用CSS伪类实现毛玻璃效果
效果图: 思路: 内容容器需要一个before伪类,负责引用跟背景容器相同的背景图,还需要一个after伪类,用来加上半透明的白色背景.这两个伪类的层级需都为-1,而内容容器本身的层级为1,这样做可以 ...
- JavaScript HTML DOM Style flexWrap 属性
flexWrap 属性 flexWrap属性指定flex项是否应该换行. 注意:如果元素不是flex项,则flexWrap属性不起作用. 如果必要,使flex换行: document.getEleme ...
- 复习一下KVC
一. 前言 KVC(Key Value Coding)是Cocoa框架为开发者提供的非常强大的工具,简单解释为:键值编码.它依赖于Runtime,在OC的动态性方面发挥了重要作用. 它主要的功能在于直 ...