题解 P8029 【[COCI2021-2022#3] Akcija】
registerGen · · 题解
在 cnblogs 中查看
注:这篇题解中涉及到的所有概念均会在其第一次出现时用 斜体 标出,有些概念给出了定义,而有些概念的含义请自行意会。
定义 状态 为选了的物品数
我们先来考虑
接下来,我们以状态
按
对于
我们需要枚举
#include <algorithm>
#include <cstdio>
using namespace std;
using ll = long long;
const int N = 2000;
struct Node { int w, d; };
struct State { int cnt; ll sum; };
inline bool operator<(const State &lhs, const State &rhs) {
return lhs.cnt == rhs.cnt ? lhs.sum > rhs.sum : lhs.cnt < rhs.cnt;
}
inline State operator+(const State &lhs, const State &rhs) {
return {lhs.cnt + rhs.cnt, lhs.sum + rhs.sum};
}
int n, k;
Node a[N + 10];
State f[N + 10][N + 10];
State ans[N + 10], nxt[N + 10];
int main() {
scanf("%d%d", &n, &k);
for (int i = 1; i <= n; i++)
scanf("%d%d", &a[i].w, &a[i].d);
sort(a + 1, a + n + 1, [](const Node &lhs, const Node &rhs) {
return lhs.d < rhs.d;
});
for (int i = n - 1; i >= 0; i--)
for (int j = 0; j <= i; j++) {
f[i][j] = f[i + 1][j];
if (a[i + 1].d > j) f[i][j] = max(f[i][j], f[i + 1][j + 1] + State({1, a[i + 1].w}));
}
int tota = 1;
for (int i = 1; i <= n; i++) {
int totn = 0;
for (int j = 1; j <= tota; j++) {
nxt[++totn] = {ans[j].cnt, ans[j].sum};
if (a[i].d > ans[j].cnt) nxt[++totn] = {ans[j].cnt + 1, ans[j].sum + a[i].w};
}
tota = min(k, totn);
nth_element(nxt + 1, nxt + tota + 1, nxt + totn + 1, [&](const State &lhs, const State &rhs) {
return rhs + f[i][rhs.cnt] < lhs + f[i][lhs.cnt];
});
for (int j = 1; j <= tota; j++) ans[j] = nxt[j];
}
sort(ans + 1, ans + k + 1, [](const State &lhs, const State &rhs) { return rhs < lhs; });
for (int i = 1; i <= k; i++)
printf("%d %lld\n", ans[i].cnt, ans[i].sum);
return 0;
}