LA 4254 Processor (二分+贪心)

ACM-ICPC Live Archive

  这道题搞了我两天,最终还是搞出来了!

  很容易就可以发现这题是二分,不过二分后怎么贪心就稍微有点难想了。贪心的方法其实很简单,就是尽量先把结束的早的任务先尽早的完成了。如果在给定的处理器速度下不能完成所有任务,那么这个速度就还不够。

  我的方法是用线段树填充尽量靠左的填充没利用的速度,根据能够填充的量,判断贪心是否能够做到。

代码如下:

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

转载于:https://www.cnblogs.com/LyonLys/archive/2013/02/21/LA_4254_Lyon.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值