当前位置: 首页 > news >正文

[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)\) :
\[ 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 <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);
    }
}

o_68541000_p0.png

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

相关文章:

  • 一、ABP框架框架摘要
  • Java-Runoob-高级教程-实例-字符串:02. Java 实例 - 查找字符串最后一次出现的位置...
  • “尝试加载 Oracle 客户端库时引发 BadImageFormatException。如果在安装 32 位 Oracle 客户端组件的情况下以 64 位模式运行,将出现此问题。”...
  • Http input plugin
  • elasticsearch+logstash+kibana部署
  • 物联网的概念
  • 漂亮数组 Beautiful Array
  • es6常用功能与异步详解(JS高级面试题)
  • python----__str__与__repr__的区别
  • OpenCV入门学习资料汇总
  • 性能测试必知必会
  • Typora + Mathpix Snip,相见恨晚的神器
  • MongoDB 介绍
  • ActiveMQ( 一) 同步,异步,阻塞 JMS 消息模型
  • Python基础之集合
  • 2017年终总结、随想
  • Android Volley源码解析
  • echarts的各种常用效果展示
  • iOS筛选菜单、分段选择器、导航栏、悬浮窗、转场动画、启动视频等源码
  • Java 9 被无情抛弃,Java 8 直接升级到 Java 10!!
  • Netty源码解析1-Buffer
  • Redash本地开发环境搭建
  • Redux系列x:源码分析
  • vagrant 添加本地 box 安装 laravel homestead
  • Vue.js-Day01
  • Webpack4 学习笔记 - 01:webpack的安装和简单配置
  • 订阅Forge Viewer所有的事件
  • 二维平面内的碰撞检测【一】
  • 模型微调
  • 我与Jetbrains的这些年
  • 如何用纯 CSS 创作一个货车 loader
  • ​LeetCode解法汇总2304. 网格中的最小路径代价
  • # 深度解析 Socket 与 WebSocket:原理、区别与应用
  • #使用清华镜像源 安装/更新 指定版本tensorflow
  • (4) openssl rsa/pkey(查看私钥、从私钥中提取公钥、查看公钥)
  • (8)STL算法之替换
  • (9)YOLO-Pose:使用对象关键点相似性损失增强多人姿态估计的增强版YOLO
  • (HAL库版)freeRTOS移植STMF103
  • (八)Flask之app.route装饰器函数的参数
  • (二)fiber的基本认识
  • (十)DDRC架构组成、效率Efficiency及功能实现
  • (一) springboot详细介绍
  • (一)SpringBoot3---尚硅谷总结
  • (转)AS3正则:元子符,元序列,标志,数量表达符
  • ***linux下安装xampp,XAMPP目录结构(阿里云安装xampp)
  • .NET Core WebAPI中使用swagger版本控制,添加注释
  • .Net通用分页类(存储过程分页版,可以选择页码的显示样式,且有中英选择)
  • .php文件都打不开,打不开php文件怎么办
  • @Data注解的作用
  • [ Linux Audio 篇 ] 音频开发入门基础知识
  • [AIGC] Java 和 Kotlin 的区别
  • [AIGC] Redis基础命令集详细介绍
  • [android] 请求码和结果码的作用
  • [C# WPF] DataGrid选中行或选中单元格的背景和字体颜色修改
  • [C# 开发技巧]如何使不符合要求的元素等于离它最近的一个元素