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

Building Bridges(搭建桥梁)

题目:link,点击这里喵。

简要题意:

nnn 根柱子依次排列,每根柱子都有一个高度。第 iii 根柱子的高度为 hih_ihi

现在想要建造若干座桥,如果一座桥架在第 iii 根柱子和第 jjj 根柱子之间,那么需要 (hi−hj)2(h_i-h_j)^2(hihj)2​​ 的代价。

在造桥前,所有用不到的柱子都会被拆除,因为他们会干扰造桥进程。第 iii 根柱子被拆除的代价为 wiw_iwi,注意 wiw_iwi 不一定非负,因为可能政府希望拆除某些柱子。

现在政府想要知道,通过桥梁把第 111 根柱子和第 nnn 根柱子连接的最小代价。注意桥梁不能在端点以外的任何地方相交。

对于 100%100\%100% 的数据,有 2≤n≤105;0≤hi,∣wi∣≤1062\le n\le 10^5;0\le h_i,\vert w_i\vert\le 10^62n105;0hi,wi106

解法:

首先可以想到 O(n2)O(n^2)O(n2)dpdpdp,记 Sn=∑i=1nwiS_n=\sum_{i=1}^nw_iSn=i=1nwi,我们有:
dpi=dpj+(hi−hj)2+Si−1−Sjdp_i=dp_j+(h_i-h_j)^2+S_{i-1}-S_j dpi=dpj+(hihj)2+Si1Sj 观察,想到斜率优化,移项化简:
dpi−hi2−Si−1=−2hjhi−Sj+hj2+dpjdp_i-h_i^2-S_{i-1}=-2h_jh_i-S_j+h_j^2+dp_j dpihi2Si1=2hjhiSj+hj2+dpj令:
{k=−2hjb=−Sj+hj2+dpjdpi=khi+b+hi2+Si−1\begin{cases} k=-2h_j \\ b=-S_j+h_j^2+dp_j\\ dp_i=kh_i+b+h_i^2+S_{i-1} \end{cases}k=2hjb=Sj+hj2+dpjdpi=khi+b+hi2+Si1
我们就能构建出一些关于 dpidp_idpi 一次函数,其中 hi2+Si−1h_i^2+S_{i-1}hi2+Si1 是在计算 dpidp_idpi 时处理的,可以把它认为是 “静态” 的,显然为了让 dpidp_idpi 尽量小,我们应当让 khi+bkh_i+bkhi+b 尽量小。

我们直接使用李超线段树来维护直线方便转移即可,几乎就是模板题了。

#include <bits/stdc++.h>#define inf 0x3f3f3f3f
#define infll 0x3f3f3f3f3f3f3f3f
typedef long long lnt;using namespace std;struct my_stream {lnt x;operator lnt() {scanf("%lld", &x);return x;}
} ___read;
#define input() ___readconst int N = 4e6 + 10;
const lnt MAX_T = 2e6;int cmp(lnt x, lnt y) {if (x - y == 0) return 0;return x > y ? 1 : -1;
}struct line {lnt k, b;line() = default;line(lnt _b, lnt _k) : b(_b), k(_k) {}lnt operator()(lnt x) const { return k * x + b; }
} f[N];struct TTT {struct node {node *lf, *rt;int id;} _new[N], *rt;lnt _top;node *newnode() { return &_new[++_top]; }lnt max(lnt a, lnt b, lnt x) {lnt pd = cmp(f[a](x), f[b](x));if (pd == 0) return min(a, b);else if (pd == 1) return a;else return b;}void update(node *&cur, lnt l, lnt r, int id) {if (cur == NULL) cur = newnode();lnt mid = (l + r) >> 1;if (cur->id == 0) {cur->id = id;return;} else {if (max(cur->id, id, mid) == id) swap(cur->id, id);if (l == r - 1) return;if (max(cur->id, id, r - 1) == id) update(cur->rt, mid, r, id);else if (max(cur->id, id, l) == id) update(cur->lf, l, mid, id);}}lnt query(node *cur, lnt l, lnt r, lnt x) {if (cur == NULL) return -infll;lnt mid = (l + r) >> 1;lnt a = 0;if (x < mid) a = query(cur->lf, l, mid, x);else if (x >= mid) a = query(cur->rt, mid, r, x);return ::max(a, f[cur->id](x));}} t;lnt h[N], s[N], dp[N];lnt pf(lnt x) { return x * x; }int main() { //lnt n = input();for (lnt i = 1; i <= n; ++i) h[i] = input();for (lnt i = 1; i <= n; ++i) s[i] = s[i - 1] + input();f[1] = line(s[1] - pf(h[1]), h[1] * 2);t.update(t.rt, 0, MAX_T, 1);f[n + 1] = line(-infll, 0);t.update(t.rt, 0, MAX_T, n + 1);for (lnt i = 2; i <= n; ++i) {dp[i] = -t.query(t.rt, 0, MAX_T, h[i]) + pf(h[i]) + s[i - 1];f[i] = line(s[i] - pf(h[i]) - dp[i], h[i] * 2);t.update(t.rt, 0, MAX_T, i);}printf("%lld\n", dp[n]);return 0;
}

Tips:

  • 本题不用 double 喵。
  • 本题要开 long long 喵。
  • 本题李超线段树维护的是 hhh,所以其范围是 10^6 喵。
  • 文章中的李超线段树将所有都取负然后计算时再反过来。
http://www.dtcms.com/a/273040.html

相关文章:

  • 【技术追踪】SynPo:基于高质量负提示提升无训练少样本医学图像分割性能(MICCAI-2025)
  • UE5源码模块解析与架构学习
  • 学习软件测试的第十四天(移动端)
  • pyqt-3(QSS、读取带qrc的ui、信号与槽函数)
  • CMake指令:add_custom_command和add_custom_target详解
  • Vue响应式原理五:响应式-自动收集依赖
  • OKHttp 核心知识点详解
  • 页面html,当鼠标点击图标,移开图标,颜色方块消失
  • 【牛客刷题】跳台阶(三种解法深度分析)
  • doker以及网站案例
  • 快速上手ASP .NET Core 8与MongoDB整合
  • 200W 以内的伺服电机 典型应用场景
  • C语言顺序表:从零开始,解锁数据结构之门!
  • YOLO系列pt导出不同onnx方法
  • Renren框架DistributeLock排他锁实现详解
  • 企业内网系统:从传统开发到智能赋能的进化之路
  • 安达发|医疗器械行业APS自动排单:智能化生产管理的未来之路
  • useRef跨渲染周期存储
  • 数据结构 --- 队列
  • 10.Docker安装mysql
  • chatgpt是怎么诞生的,详解GPT1到GPT4的演化之路及相关背景知识
  • dexie 前端数据库封装
  • 使用快捷键迅速校准多个通道 | IPEmotion
  • 软件技术:柯里化
  • 《PyQt6-3D应用开发技术文档》
  • 仿豆包智能输入框实现
  • python基础25_某大网校(下)处理json数据以及保存题库
  • 安全访问云端内部应用:用frp的stcp功能解决SSH转发的痛点
  • Linux驱动开发(platform 设备驱动)
  • 老题新解|矩阵转置