T3:最大子集
本题是 01背包 的变种题
记 dp[i] 表示选到的奶牛的智商总和为 \(i\) 时对应的情商总和的最大值
这里由于 \(x\) 可能是负数,所以需要将 \(i\) 向后偏移 \(3e5\)
特别地,在转移时,当 \(x>0\) 时,倒序枚举 \(i\);而当 \(x < 0\) 时,则需要正序枚举 \(i\)
理由也很简单,是为了保证 \(dp\) 转移的无后效性
原题:[USACO03FALL]Cow Exhibition G
代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
inline void chmax(int& x, int y) { if (x < y) x = y; }
int dp[600005];
int main() {
int n;
cin >> n;
memset(dp, 0xcf, sizeof dp);
const int S = 300000, M = S*2;
dp[S] = 0;
rep(i, n) {
int x, y;
cin >> x >> y;
if (x >= 0) {
for (int j = M; j >= x; --j) {
chmax(dp[j], dp[j-x]+y);
}
}
else {
for (int j = 0; j-x <= M; ++j) {
chmax(dp[j], dp[j-x]+y);
}
}
}
int ans = 0;
for (int i = S; i <= M; ++i) {
if (dp[i] >= 0) {
chmax(ans, i+dp[i]-S);
}
}
cout << ans << '\n';
return 0;
}
T4:接单
可以考虑反悔贪心:
- 先将每个工作按时间大小排好序,优先做截止时间靠前的工作
- 用小根堆 \(q\) 维护所选择的工作
- 扫描每个工作,若当前工作已经超过截止时间的话,那么为了让报酬最大化,(注意到每个时间点只能做一个工作),若当前的工作利润比前面选的工作中报酬最小的更高的话,那么就可以用当前的工作替换掉;否则直接选即可
原题:[USACO09OPEN]Work Scheduling G
代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
using P = pair<int, int>;
using ll = long long;
int main() {
int n;
cin >> n;
vector<P> p(n);
rep(i, n) cin >> p[i].first >> p[i].second;
sort(p.begin(), p.end());
ll ans = 0;
priority_queue<int, vector<int>, greater<int>> q;
for (auto [d, v] : p) {
if (d <= q.size()) {
int u = q.top(); q.pop();
if (v > u) ans += v-u;
}
else ans += v;
q.push(v);
}
cout << ans << '\n';
return 0;
}
浙公网安备 33010602011771号