LOJ#2306 蔬菜
补充一个题意不太清楚的地方:蔬菜坏掉是假设蔬菜都有标号,那么特定标号的蔬菜就会在特定时间坏掉。如果你及时卖了它们,那么那一天就不会有新的蔬菜坏掉。
结论1:如果我们知道了k天的答案,那么我们直接扔掉若干个最小的蔬菜即可获得k - 1天的答案。
证:因为能在k天卖的一定能在k - 1天卖.....
推论1:只要求100000天卖哪些蔬菜即可。
结论2:最贵的菜越晚卖越好。
证:因为它最贵,所以是一定要卖的。我们要让别的菜尽量卖的多,晚卖有决策包容性。
推论2:按照从贵到廉考虑蔬菜,每个菜越晚卖越好。
结论3:可以把每个蔬菜按照变质天数分类,当天变质的蔬菜能够出售的时间是第一天到当天。
推论3:假如把每种菜按照变质天数分类,那么有额外奖励的蔬菜应该在最后一天。
证:因为额外奖励比正常蔬菜贵,所以一定会优先卖它。由结论2可知应放在最后。
然后算法就出来了。分类之后按顺序放蔬菜。每天维护从它开始向前,第一个空闲的地方。可以用并查集实现。
每天能放多少菜要特别注意,代码实现上我用总数 - 之前应该留下的菜数来限制。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <bits/stdc++.h> 2 3 inline char gc() { 4 /*static char buf[1000000], *p1, *p2; 5 if(p1 == p2) p2 = (p1 = buf) + fread(buf, 1, 1000000, stdin); 6 return (p1 == p2) ? EOF : *p1++;*/ return getchar(); 7 } 8 9 template <class T> inline void read(T &x) { 10 x = 0; 11 char c = gc(); 12 bool f = 0; 13 while(c < '0' || c > '9') { 14 if(c == '-') f = 1; 15 c = gc(); 16 } 17 while(c >= '0' && c <= '9') { 18 x = x * 10 + c - 48; 19 c = gc(); 20 } 21 if(f) x = (~x) + 1; 22 return; 23 } 24 25 typedef long long LL; 26 const int N = 100010; 27 28 struct Node { 29 int val, d, id, cnt, flag; 30 Node(int V = 0, int D = 0, int ID = 0, int C = 0, int F = 0) { 31 val = V; 32 d = D; 33 id = ID; 34 cnt = C; 35 flag = F; 36 } 37 inline bool operator <(const Node &w) const { 38 if(val != w.val) 39 return val < w.val; 40 return d < w.d; 41 } 42 }; 43 44 std::priority_queue<Node> Q, Q2; 45 int a[N], s[N], c[N], x[N], fa[N], rest[N]; 46 LL ans[N]; 47 48 int find(int x) { 49 if(x == fa[x]) return x; 50 return fa[x] = find(fa[x]); 51 } 52 53 inline void del(LL &a) { 54 Node t = Q2.top(); 55 Q2.pop(); 56 a += t.val; 57 t.cnt--; 58 if(t.cnt) Q2.push(t); 59 return; 60 } 61 62 int main() { 63 64 int n, m, k, lm = 100000; 65 read(n); read(m); read(k); 66 for(int i = 1; i <= lm; i++) { 67 fa[i] = i; 68 rest[i] = m; 69 } 70 for(int i = 1; i <= n; i++) { 71 read(a[i]); read(s[i]); read(c[i]); read(x[i]); 72 LL day; 73 if(!x[i]) { 74 day = lm; 75 } 76 else { 77 day = std::min((c[i] - 1) / x[i] + 1, lm); 78 } 79 Q.push(Node(a[i] + s[i], day, i, 1, 0)); 80 if((day - 1) * x[i] + 1 < c[i]) { /// the last day have rest 81 Q.push(Node(a[i], day, i, c[i] - 1 - x[i] * (day - 1), 0)); 82 } 83 if(day > 1 && x[i]) { 84 Q.push(Node(a[i], day - 1, i, x[i] * (day - 1), 1)); 85 } 86 //c[i]--; 87 } 88 89 //int Last = 0, Cnt = 0; 90 91 int tot = 0; 92 while(Q.size()) { 93 Node t = Q.top(); 94 Q.pop(); 95 int now = find(t.d); 96 while(now && t.cnt) { 97 LL large; 98 if(t.flag) large = std::min(t.cnt, std::min(t.cnt - x[t.id] * (now - 1), rest[now])); 99 else if(x[t.id]) large = std::min(t.cnt, std::min(x[t.id], rest[now])); 100 else large = std::min(t.cnt, rest[now]); 101 102 ans[lm] += t.val * large; 103 tot += large; 104 Q2.push(Node(-t.val, 0, t.id, large)); 105 rest[now] -= large; 106 t.cnt -= large; 107 if(!rest[now]) { 108 fa[now] = find(now - 1); 109 } 110 now = find(now - 1); 111 } 112 } 113 114 115 int day = (tot - 1) / m + 1; /// need (day) to sell the vegetables 116 117 for(int i = lm - 1; i >= day; i--) { 118 ans[i] = ans[lm]; 119 } 120 ans[day - 1] = ans[day]; 121 for(int T = 1; T <= tot - m * (day - 1); T++) { 122 del(ans[day - 1]); 123 } 124 125 for(int i = day - 2; i >= 1; i--) { 126 ans[i] = ans[i + 1]; 127 for(int T = 1; T <= m; T++) { 128 del(ans[i]); 129 } 130 } 131 132 for(int i = 1; i <= k; i++) { 133 int t; 134 read(t); 135 printf("%lld\n", ans[t]); 136 } 137 138 return 0; 139 }