区间移位

问题描述
  数轴上有n个闭区间D1,…,Dn。其中区间Di用一对整数[aibi]来描述,满足ai < bi。已知这些区间的长度之和至少有10000。所以,通过适当的移动这些区间,你总可以使得他们的“并”覆盖[0, 10000]——也就是说[0, 10000]这个区间内的每一个点都落于至少一个区间内。
  你希望找一个移动方法,使得位移差最大的那个区间的位移量最小。
  具体来说,假设你将Di移动到[ai+cibi+ci]这个位置。你希望使得maxi |ci|  最小。
输入格式
  输入的第一行包含一个整数n,表示区间的数量。
  接下来有n行,每行2个整数ai,  bi,以一个空格分开,表示区间[aibi]。保证区间的长度之和至少是10000。
输出格式
  输出一个数,表示答案。如果答案是整数,只输出整数部分。如果答案不是整数,输出时四舍五入保留一位小数。
样例输入
2
10 5010
4980 9980
样例输出
20
样例说明
  第一个区间往左移动10;第二个区间往右移动20。
样例输入
4
0 4000
3000 5000
5001 8000
7000 10000
样例输出
0.5
样例说明
  第2个区间往右移0.5;第3个区间往左移0.5即可。
数据规模和约定
  对于30%的评测用例,1 ≤ n ≤ 10;
  对于100%的评测用例,1 ≤ n ≤ 10000,0 ≤ ai < bi  ≤ 10000。
 
区间移位,最小是移动0.5,这个可以很容易想到,因为给出的区间端点都是整数,要使得移位最小,显然是要平分的比如两个区间之间空了1,彼此相对移动0.5,就可以填补。
所以首先所有的数据都乘以2,最后的结果再除以2即可。
要确定移动区间的大小,可以用二分来一点一点的逼近最小的移动标准,给定一个标准,判断是否可行。需要先对所有的区间进行排序,这里对区间的右端点升序排序,为啥不按左端点排序,如果按照左端点排序,可能产生错误答案,比如样例
3
0 1000
100 900
1100 10000
显然把第二个区间左移100,第一个右移100即可,如果是按照左端点升序排序,也就是给定的顺序,需要移动200才能满足,这是不对的,所以按右端点排序,但是右端点排序后可能出现误判,因为我们每到一个区间,就要判断这个区间的左端点与前面已经合并的区间最右点的关系,比如说左边已经合并的区间的右端点是100,然后我们按照右端点排序的两个区间有1000 2000和100 2100,第一个区间不需要移动的,也就是说如果给出的移动标准低于1000,可能就会误判成不可行,但是实际是可行的,所以for循环里加了个while循环寻找后面的左端点考前的区间,然后标记使用过,下次不再使用。
代码:
#include <iostream>
#include <cstdio>
#include <algorithm>

using namespace std;
typedef long long ll;
typedef pair<int,int> pa;
pa l[10001];
int n;
bool cmp(pa a,pa b) {
    if(a.second == b.second)return a.first < b.first;
    return a.second < b.second;
}
bool check(int d) {
    bool vis[100001] = {false};
    int last = 0,j = 0;///已经合并区间的最右端点
    for(int i = 0;i < n && last < 20000;i += (j == i),j = i) {
        while(j < n && (vis[j] || l[j].first - last > d)) j ++;///找到满足当前标准的左端点靠前的区间
        if(j >= n) return false;
        vis[j] = true;
        if(last - l[j].first >= d) last = max(last,l[j].second + d);///重叠部分比d大,最多往右移动d
        else {///新区间接在了last后面
            last += l[j].second - l[j].first;
        }
    }
    return last >= 20000;
}
int main() {
    scanf("%d",&n);
    for(int i = 0;i < n;i ++) {
        scanf("%d%d",&l[i].first,&l[i].second);
        l[i].first *= 2;
        l[i].second *= 2;
    }
    sort(l,l + n,cmp);
    int l = 0,r = 20000;
    while(l < r) {//二分寻找最合适标准
        int mid = (l + r) / 2;
        if(check(mid)) r = mid;
        else l = mid + 1;
    }
    if(l % 2) printf("%.1f",l / 2.0);
    else printf("%d",l / 2);
    return 0;
}
原文地址:https://www.cnblogs.com/8023spz/p/10721041.html