• Snuketoon [ABC217H]


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

    题解

    (f_{i,x}) 表示在 (T_i) 时刻在 (x) 位置,受到的最小伤害是多少

    (m_i = T_i-T_{i-1})

    (D_i=0) 为例,转移有 (f_{i,x}=minlimits_{yin [x-m_i,x+m_i]} f_{i-1,y} + min{X_i-x,0})

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

    不妨把上面的转移分成两步,先是 (f_{i,x}=minlimits_{yin [x-m_i,x+m_i]} f_{i-1,y})

    此时对于凸壳左半边斜率小于 (0) 的部分,有 (f_{i,x-1} > f_{i,x}) ,所以 (f_{i,x}=minlimits_{yin [x-m_i,x+m_i]} f_{i-1,y}=f_{i-1,x+m_i})

    同理对于右半边斜率大于 (0) 的部分,有 (f_{i,x}=f_{i-1,x-m_i})

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

    第二步是给每个 (f_{i,x}) 加上 (min{X_i-x,0}) (仍然以 (D_i=0) 为例)

    可以发现,这个操作相当于给 ([-infty,X_i]) 这段的 (f_{i,x}) 加上一个斜率为 (-1) 的一次函数

    考虑怎么维护这个凸壳:

    对于左半边斜率小于0的部分,从右到左维护若干个断点 (p_1,p_2,dots,p_k),表示 ([p_1,p_2]) 区间上凸壳斜率为 (-1)([p_2,p_3]) 上斜率为 (-2),......

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

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

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

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

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

    下面放一张图方便理解:

    (D_i=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
    ", ans);
    	return 0;
    }
    
    作者:AK_DREAM
    本文版权归作者和博客园共有,欢迎转载,但必须给出原文链接,并保留此段声明,否则保留追究法律责任的权利。
  • 相关阅读:
    柯里化函数
    函数部分应用Partial application
    001Spark文件分析测试
    001Spring4.2基本环境搭建
    Rectangle 响应按键
    jQuery打印Html页面自动分页
    jquery实现页面局部刷新
    2014 年10个最佳的PHP图像操作库--留着有用
    20 个势头最猛的开发者工具
    20+个很有用的 jQuery 的 Google 地图插件
  • 原文地址:https://www.cnblogs.com/ak-dream/p/AK_DREAM127.html
Copyright © 2020-2023  润新知