蓝桥杯 PREV-47 区间移位(二分+贪心)

题目链接:

PREV-47 区间移位

思路:

1.既然是寻得长度的最优解,那我们二分答案便可;
2.对于 c h e c k check 函数,我们自然需要检查当前的二分值是否合乎要求,即在 l e n len 长度内能否将这些线段拼凑好;
3.博主首先采用左端点越小优先级越高的贪心方法,只有80分,该思路的问题就是过于想当然,如果是求线段移动总长度之和最小,我们可以采用这种方式;
4.我们从左往右拼凑线段,目标就是填满左边的同时尽量往右延伸,在填左侧时,如何做到物尽其用呢?那就是使右端点更小的线段先填补;若先填右端点较大的,就会导致填完后的左侧边界更大,左侧边界越大就可能会导致越多的线段被覆盖且在右端点+len的情况下也移不到最右侧,那么就会造成浪费;

代码:

#include<bits/stdc++.h>

using namespace std;

const int maxn = 1e4 + 5;
struct line { 
	int l, r;
	bool operator < (const line & a) const {
		return r == a.r ? l < a.l : r < a.r;
	}
}arr[maxn];
int n, l[maxn], r[maxn], used[maxn];
inline bool ok(int len) {
	memset(used, 0, sizeof(used));
	int rcd = 0;
	while(rcd < 20000) {
		int p = lower_bound(r, r + n, rcd - len) - r;
		while(p < n && (used[p] || l[p] > rcd + len)) ++p;
		if(p == n) return false;
		rcd = min(l[p] + len, rcd) + r[p] - l[p];	
		used[p] = true;
	}
	return true;
}

int main() {
#ifdef MyTest
	freopen("Sakura.txt", "r", stdin);
#endif
	scanf("%d", &n);
	for(int i = 0; i < n; i++) {
		scanf("%d %d", &arr[i].l, &arr[i].r);
		arr[i].l <<= 1, arr[i].r <<= 1;
	}
	sort(arr, arr + n);
	for(int i = 0; i < n; i++) l[i] = arr[i].l, r[i] = arr[i].r;
	int lf = 0, rt = 1e8, ans = 0;
	while(lf <= rt) {
		int mid = (lf + rt) >> 1;
		if(ok(mid)) ans = mid, rt = mid - 1;
		else lf = mid + 1;
	}
	cout << ans / 2.0;
	return 0;
}
发布了356 篇原创文章 · 获赞 12 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_45228537/article/details/104384219
今日推荐