http://acm.hdu.edu.cn/showproblem.php?pid=5699
此题满足二分性质,关键在于如何判断当前的时间值可以满足所有的运送方案中的最长的时间。
对于每一次枚举出的k,对于朴素时间就不大于这个值的方案显然满足,剩下的方案耗费的时间都大于k,换句话说剩下的方案如果想满足k就必须要通过传送点,才有可能实现。
对于 (Li,Ri) 通过传送点(L,R)的时间就是 abs(Ri-R)+abs(Li-L)
传送点与路径的情况有四种
L_________R L______________R L___________R L_________R
Li_____________Ri Li_________Ri Li_________Ri Li_________Ri
一开始思维僵化固执的以为L的值一定出现在Li的右侧,所以用了贪心来决策,后来才意识到其实可以从出发点先走到传送点,从传送点再走到目的点!
我们不难得出式子 abs(Ri-R)+abs(Li-L)<=k
将abs拆开就是四个式子:
- Ri-R+Li-L<=k;
- Ri-R-Li+L<=k;
- R-Ri+Li-L<=k;
- R-Ri-Li+L<=k;
由1,4得 : 5.Ri+Li-k<=R+L<=k+Li+Ri
由2,3得: 6. Li-Ri-k<=R-L<=Li-Ri+k
虽然可以有这两个式子直接推出LR的范围
7. Li-k<=L<=Li+k
8. Ri-k<=R<=Ri+k
但是这并不是一个充要条件!
5,6成立则7,8也成立,但是7,8成立5,6却不一定成立,所以无法直接依据7,8判定。
我们不难统计出这四个边界得值,最后判断一下是否存在合法的区间使得LR存在即可
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define inf 0x3f3f3f3f 4 int pl[1000005],pr[1000005]; 5 bool ok(int k,int m) 6 { 7 int i,j,a=-inf,c=-inf,b=inf,d=inf; 8 for(i=1;i<=m;++i){ 9 if(pr[i]-pl[i]<=k) continue; 10 a=max(a,pl[i]+pr[i]-k); 11 c=max(c,pl[i]-pr[i]-k); 12 b=min(b,pl[i]+pr[i]+k); 13 d=min(d,pl[i]-pr[i]+k); 14 } 15 return a <= b&&c <= d; 16 } 17 18 int main() 19 { 20 int n,m,i,j,k; 21 while(cin>>n>>m){ 22 for(i=1;i<=m;++i){ 23 scanf("%d%d",pl+i,pr+i); 24 if(pl[i]>pr[i]) 25 swap(pl[i],pr[i]); 26 } 27 int l=0,r=n,mid; 28 while(l<r){ 29 mid=l+(r-l)/2; 30 if(ok(mid,m)) r=mid; 31 else l=mid+1; 32 }cout<<l<<endl; 33 } 34 return 0; 35 }