这道题搞了我两天,最终还是搞出来了!
很容易就可以发现这题是二分,不过二分后怎么贪心就稍微有点难想了。贪心的方法其实很简单,就是尽量先把结束的早的任务先尽早的完成了。如果在给定的处理器速度下不能完成所有任务,那么这个速度就还不够。
我的方法是用线段树填充尽量靠左的填充没利用的速度,根据能够填充的量,判断贪心是否能够做到。
代码如下:
View Code
1 #define REP(i, n) for (int i = 0; i < (n); i++) 2 3 #define lson l, m, rt << 1 4 #define rson m + 1, r, rt << 1 | 1 5 6 struct Task { 7 int l, r; 8 LL w; 9 Task() {} 10 Task(int _l, int _r, LL _w) : l(_l), r(_r), w(_w) {} 11 bool operator < (const Task &x) const { 12 if (r != x.r) return r < x.r; 13 return l > x.l; 14 } 15 } task[N]; 16 LL rest[M << 2], buf[M << 2]; 17 18 void up(int rt) { 19 rest[rt] = rest[rt << 1] + rest[rt << 1 | 1]; 20 } 21 22 void down(int rt) { 23 if (buf[rt]) { 24 int ls = rt << 1, rs = rt << 1 | 1; 25 LL val = min(buf[rt], rest[ls]); 26 buf[rs] += val - rest[ls]; 27 rest[rs] -= val - rest[ls]; 28 buf[ls] += val; 29 rest[ls] -= val; 30 buf[rt] = 0; 31 } 32 } 33 34 void build(LL val, int l, int r, int rt) { 35 buf[rt] = 0; 36 if (l == r) { 37 rest[rt] = val; 38 return ; 39 } 40 int m = (l + r) >> 1; 41 build(val, lson); 42 build(val, rson); 43 up(rt); 44 } 45 46 LL update(LL val, int L, int R, int l, int r, int rt) { 47 int ret = 0; 48 if (L <= l && r <= R) { 49 ret = min(val, rest[rt]); 50 buf[rt] += ret; 51 rest[rt] -= ret; 52 return ret; 53 } 54 int m = (l + r) >> 1; 55 down(rt); 56 if (L <= m) { 57 ret = update(val, L, R, lson); 58 if (val - ret > 0 && m < R) { 59 ret += update(val - ret, L, R, rson); 60 } 61 } else if (m < R) { 62 ret = update(val, L, R, rson); 63 } 64 up(rt); 65 return ret; 66 } 67 68 int mL, mR; 69 70 void input(int n) { 71 int l, r; 72 LL w; 73 mL = inf; 74 mR = -inf; 75 REP(i, n) { 76 scanf("%d%d%lld", &l, &r, &w); 77 task[i] = Task(l, r - 1, w); 78 mL = min(mL, l); 79 mR = max(mR, r - 1); 80 } 81 sort(task, task + n); 82 } 83 84 bool test(LL x, int n) { 85 build(x, mL, mR, 1); 86 REP(i, n) { 87 LL tmp = update(task[i].w, task[i].l, task[i].r, mL, mR, 1); 88 if (tmp < task[i].w) return false; 89 } 90 return true; 91 } 92 93 LL work(int n) { 94 LL l = 0, r = 100000000, mk = r; 95 while (l <= r) { 96 LL m = (l + r) >> 1; 97 if (test(m, n)) mk = m, r = m - 1; 98 else l = m + 1; 99 } 100 return mk; 101 } 102 103 int main() { 104 int n, T; 105 scanf("%d", &T); 106 while (T-- && ~scanf("%d", &n)) { 107 input(n); 108 printf("%lld\n", work(n)); 109 } 110 return 0; 111 }
这题还可以用优先队列的方法来做,具体代码将尽快更新。
UPD:
用多重集来代替优先队列,代码如下:
View Code
1 #define MSET multiset 2 #define ITOR iterator 3 #define REP(i, n) for (int i = 0; i < (n); i++) 4 5 typedef pair<int, int> PII; 6 typedef vector<PII> VPII; 7 8 int r[N], d[N]; 9 bool vis[N]; 10 LL w[N]; 11 VPII timeMark; 12 13 void input(int n) { 14 timeMark.clear(); 15 REP(i, n) { 16 scanf("%d%d%lld", &r[i], &d[i], &w[i]); 17 timeMark.PB(MPR(r[i], i)); 18 timeMark.PB(MPR(d[i], i)); 19 } 20 sort(ALL(timeMark)); 21 } 22 23 LL rest[N]; 24 MSET<PII> onTask; 25 26 bool test(int x, int n) { 27 MSET<PII>::ITOR msi; 28 onTask.clear(); 29 REP(i, n) rest[i] = w[i], vis[i] = false; 30 REP(i, (n << 1) - 1) { 31 LL cur = (LL) x * (timeMark[i + 1].FI - timeMark[i].FI); 32 int id = timeMark[i].SE; 33 if (vis[id]) { 34 msi = onTask.find(MPR(d[id], id)); 35 if (msi != onTask.end()) onTask.erase(msi); 36 } else { 37 vis[id] = true; 38 onTask.insert(MPR(d[id], id)); 39 } 40 while (true) { 41 if (cur <= 0) break; 42 if (onTask.empty()) break; 43 id = (*onTask.begin()).SE; 44 if (cur > rest[id]) cur -= rest[id], rest[id] = 0ll, onTask.erase(onTask.begin()); 45 else { 46 rest[id] -= cur, cur = 0ll; 47 if (rest[id] <= 0) onTask.erase(onTask.begin()); 48 } 49 } 50 } 51 REP(i, n) if (rest[i]) return false; 52 return true; 53 } 54 55 int work(int n) { 56 int h = -1, t = 1e7 + 10, m, mk = 0; 57 while (h <= t) { 58 m = (h + t) >> 1; 59 if (test(m, n)) mk = m, t = m - 1; 60 else h = m + 1; 61 } 62 return mk; 63 } 64 65 int main() { 66 int T, n; 67 scanf("%d", &T); 68 while (T--) { 69 scanf("%d", &n); 70 input(n); 71 printf("%d\n", work(n)); 72 } 73 return 0; 74 }
——written by Lyon