Snuketoon [ABC217H]

https://atcoder.jp/contests/abc217/tasks/abc217_h

题解

fi,x 表示在 Ti 时刻在 x 位置,受到的最小伤害是多少

mi=TiTi1

Di=0 为例,转移有 fi,x=miny[xmi,x+mi]fi1,y+min{Xix,0}

观察一下样例可以发现,对于一个固定的 i ,若把所有 (x,fi,x) 当成点画在二维平面上并连接相邻点,那么图像会是一段下凸壳,也就是说 fi,x 是一个下凸的函数

不妨把上面的转移分成两步,先是 fi,x=miny[xmi,x+mi]fi1,y

此时对于凸壳左半边斜率小于 0 的部分,有 fi,x1>fi,x ,所以 fi,x=miny[xmi,x+mi]fi1,y=fi1,x+mi

同理对于右半边斜率大于 0 的部分,有 fi,x=fi1,xmi

所以这一步就相当于将凸壳左半边向左平移 mi ,右半边向右平移 mi

第二步是给每个 fi,x 加上 min{Xix,0} (仍然以 Di=0 为例)

可以发现,这个操作相当于给 [,Xi] 这段的 fi,x 加上一个斜率为 1 的一次函数

考虑怎么维护这个凸壳:

对于左半边斜率小于0的部分,从右到左维护若干个断点 p1,p2,,pk,表示 [p1,p2] 区间上凸壳斜率为 1[p2,p3] 上斜率为 2,......

对于右半边同理;额外维护一个 ans 表示斜率为 0 部分的答案

对于第一步转移,直接维护左半边和右半边的偏移量即可

对于第二步转移,以 Di=0 为例,设右半边凸壳的第一个断点为 r

如果 Xir ,那么此时 Xi 左边的部分斜率要全部 1 ,所以将 Xi 作为断点加入左半边凸壳的断点集合即可

如果 Xi>r ,那么有一段原来斜率为 1 的区间加上这个斜率为 1 的一次函数后斜率变成 0 了,更新 ans+=Xir,同时将右半边第一个断点改为 Xi ,左半边新增了断点 r

下面放一张图方便理解:

Di=1 时也同理

最后答案即为 ans

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

int n;
priority_queue<ll> q0;
priority_queue<ll, vector<ll> , greater<ll> > q1;

int main() {
	scanf("%d", &n); ll ans = 0;
	for (int i = 1, t, d, x; i <= n; i++) {
		scanf("%d %d %d", &t, &d, &x);
		if (d == 0) {
			if (x > t) ans += x-t, x = t;
			if (q1.empty() || x <= q1.top()+t) q0.push(x+t);
			else {
				ll y = q1.top()+t;
				ans += x-y;
				q0.push(y+t); 
				q1.pop(); q1.push(x-t);
			}
		} else {
			if (x < -t) ans += -t-x, x = -t;
			if (q0.empty() || x >= q0.top()-t) q1.push(x-t);
			else {
				ll y = q0.top()-t;
				ans += y-x;
				q0.pop(); q0.push(x+t);
				q1.push(y-t);
			}
		}
	}
	printf("%lld\n", ans);
	return 0;
}
posted @   AK_DREAM  阅读(172)  评论(0编辑  收藏  举报
编辑推荐:
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示