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

CF1795E Explosions? (单调栈)

传送门

题意:

有 n 个怪兽需要消灭,它们的生命值分别是 h [1],h [2]......h [n].

我们可以使用两种技能:

技能 1:选择任意一个怪兽,使其生命值降低 1 点,并且需要 1 点能量值.

技能 2:选择任意一个怪兽,使其生命值降低 x 点,需要花费 x 点能量值.

如果使用技能 2之后消灭了被选择的怪兽,那么会接着对其相邻的怪兽造成 h[ i ] - 1点伤害值. 注意:技能 2 只能使用一次!

问题:

消灭所有的怪兽最少需要花费多少能量值 ?

思路:

假设把第 i 个怪兽作为Explosion的目标,那么要求 h[1] -> h[ i ] 变成严格单调递增,h[ i ] -> h[ n ]变成严格单调递减.

我们称把 1~ i 的生命值修改为严格单调递增的代价为 L[ i ],i 到 n 的生命值修改为严格单调递减的代价是 R[ i ].

那么答案就是 min {L[ i ] + R[ i ] + h[ i ] },那么现在,问题变成了如果求出 L[ i ] 和 R[ i ].

我们只需要考虑如果求出 L[ i ]即可,因为R[ i ]可以用类似的方法求得.

考虑一个经典技术:单调栈.

做法:

单调栈:

从左到右扫一遍过去.

栈中维护一个二元组(hi,cnt)表示当前有一个怪兽血量为h[ i ],在它左边有 cnt - 1个怪兽,它们的血量从左到右单调递增且差值为 1.

栈中 h[ i ]严格单调递增.

当扫描到 i 时,实时维护一个sum,表示当前的L[ i ],如果h[ i ] > 栈顶的 h,则L[ i ] = sum,并将(hi,1)加入栈,否则,要把栈顶的(h,cnt)这cnt 个怪兽的血量全部减去 h - hi +1,才能满足条件,我们把原先的栈顶 pop.

重复这个过程,直到栈为空或者 hi > 栈顶的 h,最终,我们将(hi,cnt1)加入栈,这里的cnt1表示 1 + pop出来的cnt的和.

参考代码:

#include <bits/stdc++.h>using LL = long long;int main() {std::ios::sync_with_stdio(false);std::cin.tie(nullptr);int t;std::cin >> t;while (t--) {int n;std::cin >> n;std::vector<int> h(n);for (int i = 0; i < n; i++) {std::cin >> h[i];}std::vector<LL> L(n);std::vector<LL> R(n);for (int rot = 0; rot < 2; rot++) {std::vector<std::pair<LL, LL>> st;LL sum{};for (int i = 0; i < n; i++) {LL cnt = 1;while (!st.empty() && h[i] - cnt < st.back().first) {LL diff = st.back().first - (h[i] - cnt);sum += diff * st.back().second;cnt += st.back().second;st.pop_back();}if (cnt - 1 > h[i]) {LL extra = cnt - 1 - h[i];sum -= extra * (extra + 1) >> 1;cnt = h[i];}L[i] = sum;st.emplace_back(h[i], cnt);}std::reverse(L.begin(), L.end());std::reverse(R.begin(), R.end());std::reverse(h.begin(), h.end());std::swap(L, R);}LL ans = (LL)1e18;for (int i = 0; i < n; i++) {ans = std::min(ans, L[i] + R[i] + h[i]);}std::cout << ans << '\n';}return 0;
}
http://www.lryc.cn/news/11714.html

相关文章:

  • C++——二叉树排序树
  • 深拷贝浅拷贝的区别?如何实现一个深拷贝?
  • Linux应用编程下连接本地数据库进行增删改查系列操作
  • 图论学习03
  • 解决qt中cmake单独存放 .ui, .cpp, .h文件
  • 操作系统(day12)-- 基本分段存储,段页式存储
  • 疯狂弹出请插入多卷集的最后一张磁盘窗口
  • Spark12: SparkSQL入门
  • show profile和trance分析SQL
  • [AI生成图片] 效果最好的Midjourney 的介绍和使用
  • Vue.use( ) 的核心原理
  • idea同时编辑多行-winmac都支持
  • 亿级高并发电商项目-- 实战篇 --万达商城项目 十一(编写商品搜索功能、操作商品同步到ES、安装RabbitMQ与Erlang,配置监听队列与消息队列)
  • 数据结构概述和稀疏数组
  • 宝塔搭建实战人才求职管理系统adminm前端vue源码(三)
  • 服务器是干什么用的?
  • C++ 之结构体与共用体
  • Java基础知识汇总(良心总结)
  • InnoDB之Undo log格式
  • 一问学习StreamAPI终端操作
  • 在屎山代码中快速找到想要的代码法-锁表法(C#)
  • 网页设计html期末大作业
  • 实战打靶集锦-006-Stapler
  • 致远OAA6版安装
  • python实用脚本(六)—— pandas库的使用(生成、读取表格)
  • 字符集、ASCII、GBK、UTF-8、Unicode、乱码、字符编码、解码问题等
  • Java 布隆过滤器
  • vscode连接服务器(腾讯云)
  • IOS崩溃文件符号化实践
  • 设计模式之适配器模式与桥接模式详解和应用