题目链接
https://www.dotcpp.com/oj/problem1846.html
解题思路
二分+贪心。
大思路比较好想,但是贪心思路不好想。
二分移动的距离;
按照区间右端点从小到大排序,每次都先尝试插入未插入中右端点最小的。若此移动距离能让覆盖满区间,此距离可以;反之,不行。
另外值得注意的点:因为存在小数的情况,但是把二分换成double会严重影响复杂度,所以我们先把输入区间的左右端点乘2后再插入,最后输出的时候只需要除2即可。
AC代码
#include<bits/stdc++.h>
#define sc(x) scanf("%d",&x)
#define pr(x) printf("%d",x)
using namespace std;
const int B=20000;
typedef pair<int,int> P;
multiset<P> s;
int check(int mid){
multiset<P> tmp(s);
int now=0,flag=0;
while(!tmp.empty()){
for(multiset<P>::iterator it=tmp.begin();it!=tmp.end();it++){
flag=0;//用于记录tmp是否还有可以用来覆盖的区间
int tta=(*it).second,ttb=(*it).first;
if(tta-mid<=now && ttb+mid>=now){//可以移动到跨越now的状态
flag=1;
int len=ttb-tta;
if(tta+mid>=now) now+=len;
else now=ttb+mid;
tmp.erase(it);
break;//每次必须从tmp的头开始试着往区间里塞
}
}
if(now>=B) return 1;
if(!flag) return 0;
}
return 0;
}
int main(){
int n,a,b,l=0,r=B;
double ans;
sc(n);
for(int i=1;i<=n;i++){
sc(a);sc(b);
s.insert(P(b*2,a*2));
}
while(l<=r){
int mid=(l+r)>>1;
if(check(mid)) r=mid-1,ans=mid;
else l=mid+1;
}
cout<<ans*1.0/2.0;
}
京公网安备 11010502036488号