Codeforces1203F2. Complete the Projects (hard version) (贪心+贪心+01背包)
题目链接:传送门
思路:
对于对rating有提升的项目,肯定做越多越好,所以把$b_{i} >= 0$的项目按rating要求从小到大贪心地都做掉,得到最高的rating记为r。
对于剩余的$b_{i} < 0$的项目,因为r的范围很小,在6e4的亚子,可以考虑用01背包来做。
但是直接上01背包会WA,是因为不同项目选择的先后顺序会对结果有影响。
比如现在的r是5,有两个项目,(ai,bi)分别为(3,-3)和(3,-1),如果先做前面的项目,就会导致rating不够做后一个项目。
考虑任意两个项目i(ai,bi),j(aj,bj),先做i后做j的话,就要求初始的rating >= aj+|bi|,反之要求rating >= ai+b|j|。
显然要求的初始rating越低越好:若aj+|bi| < ai+b|j|,说明前者要求更低,此时应先做i。移项一下就可以得ai-|bi| > aj-|bj|。
所以ai-|bi|(bi<0)越大的项目,就可以越优先地做。根据这个sort一下,跑一遍01背包就出答案了。
代码:O(r*n)
#include <bits/stdc++.h> #define fast ios::sync_with_stdio(false), cin.tie(0), cout.tie(0) #define N 105 #define R 30005 #define INF 0x3f3f3f3f #define mk(x) (1<<x) // be conscious if mask x exceeds int #define sz(x) ((int)x.size()) #define mp(a,b) make_pair(a, b) #define endl '\n' #define lowbit(x) (x&-x) using namespace std; typedef long long ll; typedef double db; /** fast read **/ template <typename T> inline void read(T &x) { x = 0; T fg = 1; char ch = getchar(); while (!isdigit(ch)) { if (ch == '-') fg = -1; ch = getchar(); } while (isdigit(ch)) x = x*10+ch-'0', ch = getchar(); x = fg * x; } template <typename T, typename... Args> inline void read(T &x, Args &... args) { read(x), read(args...); } struct Node{ int a, b; bool operator < (const Node& x) const { return a < x.a; } }; int f[R<<1]; vector <Node> vpos, vneg; bool cmp(Node x, Node y) { return x.a-x.b < y.a-y.b; } int main() { int n, r; read(n, r); for (int i = 1; i <= n; i++) { int a, b; read(a, b); if (b >= 0) vpos.push_back(Node{a, b}); else vneg.push_back(Node{a, -b}); } sort(vpos.begin(), vpos.end()); sort(vneg.begin(), vneg.end(), cmp); int ans = 0; for (int i = 0; i < sz(vpos); i++) { Node tmp = vpos[i]; if (r >= tmp.a) { r += tmp.b; ans++; } } for (int i = sz(vneg)-1; i >= 0; i--) { Node tmp = vneg[i]; for (int j = max(tmp.a, tmp.b); j <= r; j++) { f[j-tmp.b] = max(f[j-tmp.b], f[j]+1); } } int res = 0; for (int i = 0; i <= r; i++) res = max(res, f[i]); ans += res; cout << ans << endl; return 0; } /* 8 15000 11031 -299 8368 -289 12459 -297 6511 -297 2628 -299 3478 -296 1050 -293 12981 -294 */