LA_4254
一般最大值最小的问题都可以通过二分来求解,这个题目也不例外。我们对处理器速度进行二分之后,问题就转化成了对于给定的处理速度,问处理器是否可以将这些问题处理完。一个贪心的思路就是每个时刻应该尽量做可以做的任务中,结束时间最早的那个,这样最起码不会使结果更糟。这样就可以枚举每个单位时间,然后去找可以做的并且结束时间最早的那个去做,直到用完这一单位时间或者无任务可做为止。最后如果发现哪个任务还没做完,就说明在这个给定的处理速度下,处理器是不能完成所有任务的。
在查找结束时间最早的可做的任务的过程中,我的代码借助了线段树。不过据AC排名来看,应该还有更简便的算法,只不过我暂时没有想到。
#include<stdio.h> #include<string.h> #include<algorithm> #include<iostream> #define MAXN 10010 #define INF 0x3f3f3f3f typedef long long LL; int N, D, tree[4 * MAXN], di[2 * MAXN], remain[MAXN]; struct A { int r, d, w; }a[MAXN]; bool cmp(const int x, const int y) { int tx = x > 0 ? a[x].r : a[-x].d, ty = y > 0 ? a[y].r : a[-y].d; return tx < ty; } void input() { scanf("%d", &N); for(int i = 1; i <= N; i ++) { scanf("%d%d%d", &a[i].r, &a[i].d, &a[i].w); di[2 * i - 2] = i, di[2 * i - 1] = -i; } std::sort(di, di + 2 * N, cmp); for(D = 1; D < N + 2; D <<= 1); memset(tree, 0, sizeof(tree[0]) * 2 * D); a[0].d = INF; } void update(int i) { for(; i ^ 1; i >>= 1) tree[i >> 1] = a[tree[i]].d < a[tree[i ^ 1]].d ? tree[i] : tree[i ^ 1]; } int gett(int i) { return i > 0 ? a[i].r : a[-i].d; } int can(int m) { for(int i = 1; i <= N; i ++) remain[i] = a[i].w; di[2 * N] = di[2 * N - 1]; for(int i = 0; i < 2 * N; i ++) { if(di[i] > 0) tree[D + di[i]] = di[i], update(D + di[i]); else tree[D - di[i]] = 0, update(D - di[i]); LL use = (LL)m * (gett(di[i + 1]) - gett(di[i])); while(use) { int id = tree[1]; if(id == 0) break; if(use >= remain[id]) { use -= remain[id], remain[id] = 0; tree[D + id] = 0, update(D + id); } else remain[id] -= use, use = 0; } } for(int i = 1; i <= N; i ++) if(remain[i]) return 0; return 1; } void process() { int min = 0, max = 10000010, mid; for(;;) { mid = (max - min) / 2 + min; if(mid == min) break; if(can(mid)) max = mid; else min = mid; } std::cout << mid + 1 << std::endl; } int main() { int t; scanf("%d", &t); while(t --) { input(); process(); } return 0; }