题目:
题解:
1.切入点:从某一时刻之后整个管道都会被填满而之前就不会,发现答案具有二段性使用二分。
2.
代码:
#include<bits/stdc++.h>
using namespace std;
const int N=100010;
using ll=long long;
int b[N];
int n,len;
pair<int,int>q[N];
pair<int,int>c[N];
bool check(int mid){
int idx=0;
for(int i=1;i<=n;i++){
int p=q[i].first,t=q[i].second;
//cout<<"p "<<p<<" "<<"t "<<t<<endl;
if(mid<t)continue;
//len从1开始
c[idx].first=max(1,p-(mid-t));
c[idx].second=min((ll)p+(mid-t),(ll)len);
//cout<<c[idx].first<<" "<<c[idx].second<<endl;
idx++;
}
sort(c,c+idx);
int st=-1,ed=-1;
for(int i=0;i<idx;i++){
//这里可以合并为一个区间的条件是连个区间有重叠的部分或者相邻
//这里记录最后一个区间的两个端点来判断是否满足条件
if(ed+1>=c[i].first)ed=max(ed,c[i].second);
//不满足的同时更新左右端点
else st=c[i].first,ed=c[i].second;
}
//cout<<mid<<" "<<st<<" "<<ed<<endl;
if(st==1&&ed==len)return true;
return false;
}
int main(){
scanf("%d%d",&n,&len);
for(int i=1;i<=n;i++){
int x,y;
scanf("%d%d",&x,&y);
q[i]={x,y};
}
int l=0,r=2e9,mid;
while(l<r){
//mid最大可能来到两个r相加的大小
mid=(ll)l+(ll)r>>1;
if(check(mid))r=mid;
else l=mid+1;
}
printf("%d",r);
return 0;
}
题后反思:
二分的mid在计算时有可能会爆数据类型:
二分时mid的大小最大会来到 2 * r 的大小,当r很大计算时将 r 和 l 转化为long long 计算。
本题通过记录最后一个区间的左右端点来判断最后的区间是否满足将管道全部覆盖。本题的关键在于将管道全部覆盖,如果使用贪心的区间合并在区间能合并为一个区间时返回正确则可能忽视此时这一个区间并没有将整个管道覆盖住。