区间移位[dfs]
time limit per test | memory limit per test | input | output |
---|---|---|---|
1.5 seconds | 256 megabytes | standard input | standard output |
Description:
数轴上有n个闭区间D1,…,Dn。其中区间Di用一对整数[ai, bi]来描述,满足ai < bi。已知这些区间的长度之和至少有10000。所以,通过适当的移动这些区间,你总可以使得他们的“并”覆盖[0, 10000]——也就是说[0, 10000]这个区间内的每一个点都落于至少一个区间内。
你希望找一个移动方法,使得位移差最大的那个区间的位移量最小。
具体来说,假设你将Di移动到[ai+ci, bi+ci]这个位置。你希望使得maxi |ci|最小。
Input
输入的第一行包含一个整数n,表示区间的数量。
接下来有n行,每行2个整数ai,bi,以一个空格分开,表示区间[ai, bi]。保证区间的长度之和至少是10000。
One Output
输出一个数,表示答案。如果答案是整数,只输出整数部分。如果答案不是整数,输出时四舍五入保留一位小数。
One Example input
2
10 5010
4980 9980
Two Example output
20
Two Example input
4
0 4000
3000 5000
5001 8000
7000 10000
Example output
0.5
Hit
第一个区间往左移动10;第二个区间往右移动20。
第2个区间往右移0.5;第3个区间往左移0.5即可。
对于30%的评测用例,1 ≤ n ≤ 10;
对于100%的评测用例,1 ≤ n ≤ 10000,0 ≤ ai < bi≤ 10000。
分析:
题意:
n
n
n个区间,若假定一个
c
i
c_i
ci,表示第
i
t
h
i_{th}
ith区间的左右边界可以扩展至[
a
i
+
c
i
,
b
i
+
c
i
]
a_i+c_i, b_i+c_i]
ai+ci,bi+ci], 要使得所有区间的并可以覆盖数轴
[
0
,
10000
]
[0,10000]
[0,10000](原来一开始理解错了啊)问
m
a
x
(
c
i
)
max(c_i)
max(ci)的最小值是多少
做法:
应该很容易可以想到要用二分,只是问题在于如何
c
h
e
c
k
check
check是否可以
u
m
m
umm
umm参考了别人的博客 (菜是原罪) ,这里加一下自己的理解,区间移位
先对原区间进行排序,优先将右端点升序排序,若右端点相等将左端点升序排序
之后遍历每一个区间
在遍历
i
t
h
i_{th}
ith区间时, 可以求出从左往右第一个符合条件(即还没有计算过且可以被覆盖的)的下标
然后更新到目前为止最远可以覆盖到的右端点,即以下代码中的
a
n
s
ans
ans
要注意到的是,因为上一个区间如果可以被覆盖,那么前面所有被覆盖的应该都是连续的
也就是说相当于前面所有区间变成一块大区间,因此可以直接更新最右端点可以覆盖到的
如果最终可以到达的右端点
a
n
s
>
=
10000
ans >= 10000
ans>=10000,说明二分得到的数还有可能继续减小
Code:
#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <string>
#include <cstdio>
#include <vector>
#include <bitset>
#include <cmath>
#include <ctime>
#include <queue>
#include <stack>
#include <set>
#include <map>
using namespace std;
typedef long long ll;
const int maxn = 1e4 + 5;
const int inf = 0x3f3f3f3f;
struct node{
int l, r;
bool operator<(const node &ope) const { // r升序为主
return r == ope.r ? l < ope.l : r < ope.r;
}
}p[maxn];
bool vis[maxn];
bool check(double x, int n) {
x *= 0.1; double ans = 0;
memset(vis, false, sizeof(vis));
for(int i = 1, j = 1; i <= n && ans < 10000; j = i) {
while(j <= n && (vis[j] || p[j].l - ans > x)) j++; // 找到第一个符合的
if(j > n) return false;
vis[j] = true;
if(ans - p[j].l >= x) // 重叠超过x,右边可以延伸
ans = max(ans, p[j].r + x);
else
ans += p[j].r - p[j].l; // 右边不能延伸
if(i == j) i++; // 同一个位置
}
return ans >= 10000;
}
int main() {
int n;
scanf("%d", &n);
for(int i = 1; i <= n; ++i) {
scanf("%d%d", &p[i].l, &p[i].r);
}
sort(p + 1, p + 1 + n);
int l = 0, r = 100000, mid;
while(l < r) {
mid = (l + r) >> 1;
if(check(mid, n)) r = mid;
else l = mid + 1;
}
if(l % 10) printf("%.1f\n", l * 0.1);
else printf("%d\n", (int)(l*0.1));
return 0;
}