博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
[LOJ 6213]「美团 CodeM 决赛」radar
阅读量:5014 次
发布时间:2019-06-12

本文共 3471 字,大约阅读时间需要 11 分钟。

「美团 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)\) :

\[ dp_i=\max_{j<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\) 就可以了.

第二种转移需要拆一拆...

\[ \begin{aligned} 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 
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
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
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); }}

o_68541000_p0.png

转载于:https://www.cnblogs.com/rvalue/p/10640894.html

你可能感兴趣的文章
UVALive 4128 Steam Roller 蒸汽式压路机(最短路,变形) WA中。。。。。
查看>>
记忆--1.致我们不可缺少的记忆
查看>>
lintcode28- Search a 2D Matrix- easy
查看>>
react项目
查看>>
C# 万年历 农历 节气 节日 星座 星宿 属相 生肖 闰年月 时辰(转)
查看>>
A Simple Tree Problem
查看>>
Modular Inverse [ZOJ 3609]
查看>>
MySQL性能测试工具之mysqlslap使用详解
查看>>
深入理解jsonp跨域请求原理
查看>>
regsvr32注册COM组件失败
查看>>
jmeter,CSV数据加载、数据库连接、正则
查看>>
(独孤九剑)--正则表达式
查看>>
MySQL学习点滴 --分区表
查看>>
4.6.1 测试基础
查看>>
洛谷 P2486 [SDOI2011]染色
查看>>
oo第三单元总结
查看>>
leetcode : Count and Say [基本功]
查看>>
洛谷 P2485 [SDOI2011]计算器 解题报告
查看>>
c#访问存储过程
查看>>
Slickflow.NET 开源工作流引擎基础介绍(三) -- 基于HTML5/Bootstrap的Web流程设计器
查看>>