759 字
4 分钟
abc440 E 题解

原题链接

Problem Statement#

There are 1010010^{100} cookies of each of NN types. The deliciousness per cookie of the ii-th type is AiA_i.

You will choose a total of KK cookies from these. Two ways of choosing cookies are considered the same if and only if the multisets of types of chosen cookies match.

For each of the (N+K1K)\binom{N+K-1}{K} ways of choosing, consider the sum of deliciousness of the chosen cookies. Let S1,S2,S_1,S_2,\dots be these sums in descending order, with duplicates included. Find S1,,SXS_1,\dots,S_X.

简要题意#

nn 个价值为 AiA_i 的物品,每个物品无个数限制,求选 kk 个物品的 前 XX 大价值

题解#

我们可以根据当前最大方案依次推导小于当前价值的方案

Ai{A_i} 从大到小排序,

A1A2A3A_1 \rArr A_2 \rArr A_3 等价与 A1A3A_1 \rArr A_3 ,那么我们记录 A1A_1 的数量,每次下放只下放 A1A_1,总价值 A1+Ai-A_1 + A_i

又因求前 XX 大,所以每次只下放一个即可,且 A1A2,A1A3A_1 \rArr A_2, A_1 \rArr A_3 的操作顺序一定是先 A2A_2A3A_3 的,那么我们记录当前下放的最大值,就可以使得小值不会拓展到大值

复杂度 O(Xnlog(Xn))\Omicron(X n \log (X n))提交链接

34 collapsed lines
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int N = 1e5 + 5;
int n, m, k;
ll a[N];
priority_queue<array<ll, 3>> _S;
void solve() {
cin >> n >> m >> k;
for(int i = 1; i <= n; i++) cin >> a[i];
sort(a + 1, a + 1 + n, greater());
_S.push({a[1] * m, m, 2});
while(k > 0) {
auto [val, m, c] = _S.top(); _S.pop();
cout << val << endl;
k--;
if(m > 0) {
for(int i = c; i <= n; i++)
_S.push({val - a[1] + a[i], m - 1, i});
}
}
assert(k == 0);
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr), cout.tie(nullptr);
// freopen("A.in", "r", stdin);
// freopen("A.out", "w", stdout);
int T = 1;
// cin >> T;
while(T--) solve();
}

复杂度更优的解#

但是,这样的复杂度还是太坏了,在 nn 较大的时候很容易T掉 可以发现我们每次拓展都是拓展了 nn 个,且如果 AnA_n 比较小的时候,拓展到这里显然是没有用的,我们可以考虑先拓展相邻的,等下一次拓展再到后面

更为形式化的: A1A3A_1 \rArr A_3 可以变为 A1A2A3A_1 \rArr A_2 \rArr A_3

且我们拓展到 A2A_2 的时候一定是不劣的

考虑记录上一次转移了多少,以及当前转移了多少;每次尝试转移到当前层或者直接转移到下一层即可

由于每次只拓展 22 个,所以我们的复杂度上限为 O(Xlog(2X))\Omicron(X \log (2X))提交链接

38 collapsed lines
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int N = 1e5 + 5;
int n, m, k;
ll a[N];
priority_queue<array<ll, 4>> _S; // val, c, cur, pre
void solve() {
cin >> n >> m >> k;
for(int i = 1; i <= n; i++) cin >> a[i];
sort(a + 1, a + 1 + n, greater());
_S.push({a[1] * m, 2, 0, m});
while(k > 0) {
auto [val, c, cur, pre] = _S.top(); _S.pop();
cout << val << endl;
k--;
if(m > 0) {
if(pre > 0) {
_S.push({val - a[c - 1] + a[c], c, cur + 1, pre - 1});
}
if(cur > 0 && c + 1 <= n) {
_S.push({val - a[c] + a[c + 1], c + 1, 1, cur - 1});
}
}
}
assert(k == 0);
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr), cout.tie(nullptr);
// freopen("A.in", "r", stdin);
// freopen("A.out", "w", stdout);
int T = 1;
// cin >> T;
while(T--) solve();
}
abc440 E 题解
https://dk-qwq.github.io/blog/posts/at_abc440_e/
作者
dk-qwq
发布于
2026-01-16
许可协议
CC BY-NC-SA 4.0