問題描述
數軸上有
n個閉區間
D1,…,
Dn。其中區間
Di用一對整數[
ai,
bi]來描述,滿足
ai <
bi。已知這些區間的長度之和至少有10000。所以,通過適當的移動這些區間,你總可以使得他們的“並”覆蓋[0, 10000]——也就是說[0, 10000]這個區間內的每一個點都落於至少一個區間內。
你希望找一個移動方法,使得位移差最大的那個區間的位移量最小。
具體來說,假設你將 Di移動到[ ai+ ci, bi+ ci]這個位置。你希望使得max i | ci| 最小。
你希望找一個移動方法,使得位移差最大的那個區間的位移量最小。
具體來說,假設你將 Di移動到[ ai+ ci, bi+ ci]這個位置。你希望使得max i | ci| 最小。
輸入格式
輸入的第一行包含一個整數n,表示區間的數量。
接下來有n行,每行2個整數ai, bi,以一個空格分開,表示區間[ ai, bi]。保證區間的長度之和至少是10000。
接下來有n行,每行2個整數ai, bi,以一個空格分開,表示區間[ ai, bi]。保證區間的長度之和至少是10000。
輸出格式
輸出一個數,表示答案。如果答案是整數,只輸出整數部分。如果答案不是整數,輸出時四舍五入保留一位小數。
樣例輸入
2
10 5010
4980 9980
10 5010
4980 9980
樣例輸出
20
樣例說明
第一個區間往左移動10;第二個區間往右移動20。
樣例輸入
4
0 4000
3000 5000
5001 8000
7000 10000
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。
對於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; }