AT_utpc2020_a Row of Tents题解
原题链接:Row of Tents
很具有代表性的二分答案题,思路简洁,检查函数好写,适合初学二分答案练手,和 P2678 跳石头 异曲同工。难度为普及/提高-,黄。
题目大意(抽象向)
一个有效长度为 \(L\) 数轴上有个 \(n\) 坐标,坐标 \(x_i\) 有对应的赋值 \(a_i\)。原点有一个可移动点 \(u\),有固定的初始值 \(T\),一旦到之前给出的坐标 \(x_i\),\(T\) 会减去 \(a_i\),一旦 \(T\) 在某个坐标小于 \(0\),则 \(T\) 不合法。特别的,当 \(u\) 未在之前给出的坐标且 \(T\) 小于初始值时,\(T\) 会加且仅加上 \(1\)。求出最小的合法的 \(T\)。
正解思路(详细向)
不难证明在给出坐标固定的情况下,随着 \(T\) 的增加,可行性会变大。或者说,如果 \(T_0\) 合法,那么大于 \(T_0\) 的所有 \(T\) 的取值一定合法;如果 \(T_0\) 不合法,那么小于 \(T_0\) 的所有 \(T\) 的取值一定不合法。答案的规律单调,考虑二分。
二分答案下界为 \(0\)(没有给定坐标时),上界为 \(\sum{a_i}\)(给定坐标连在一起时)。二分的检查函数也十分好想,只需要从头到尾扫一遍,如果发现 \(T\) 小于 \(0\),立刻返回 false
,否则返回 true
。要注意当 \(T\) 大于等于初始值时一定不可以再加 \(1\)。
二分复杂度为 \(O(\log\sum{a_i})\),扫一遍有效长度复杂度为 \(O(n)\) 而不是 \(O(L)\),因为可以对两个坐标作差来取得 \(T\) 的恢复值。程序总复杂度为 \(O(n\log\sum{a_i})\)。
分析结束,下面是代码,注意数据范围,要开 long long
。
最终代码(丑陋向)
#include<bits/stdc++.h>
#define LL long long
using namespace std;
const int maxn = 200005;
int n,L;
LL l = 0,r = 0; // 二分上下界
struct node{
int x,v; // 坐标与赋值
}a[maxn];
bool check(LL T0){ // 核心代码 2
int T = T0;
for(int i = 1;i <= n;++i){
int dx = a[i].x - a[i - 1].x;
if(T + dx > T0) T = T0;
// 注意,气力最高只能为初始值
else T += dx; // 处理空坐标增值
T -= a[i].v; // 处理气力减值
if(T < 0) return 0;
}
return 1;
}
int main(){
scanf("%d %d",&n,&L);
for(int i = 1;i <= n;i++){
scanf("%d %d",&a[i].x,&a[i].v);
r += a[i].v;
}
while(l <= r){ //核心代码 1
LL mid = (l + r) / 2;
if(!check(mid))
l = mid + 1; // 我喜欢这样写
else r = mid - 1; // 建议固定模板
}
printf("%d",l);
return 0;
}
蒟蒻的第一篇题解,觉得不错就点个赞吧 www