Search for a command to run...
Progressive hints first, then the full explanation and implementation when you're ready to cash out.
Review status
AI-generated and still unreviewed. Double-check the details before internalizing them.
Hints
Open only as much as you need to keep the solve alive.
Think in terms of maximizing the total value of free products, not directly minimizing the paid cost. The answer is .
A voucher with value makes exactly one product free, but it also “spends” other products in the same group. So small vouchers are much stronger than large vouchers.
Sort the product prices in decreasing order. Expensive products are the ones you most want to make free, but a voucher of size needs a block of unused products where the cheapest one in that block becomes free.
Use vouchers in increasing order of . For a voucher of size , take the next most expensive unused products. The cheapest among those is the last one in that block, and that is the free one.
After sorting descending and ascending, keep a pointer . For each voucher size , if , add to the free sum and move by . If there are not enough unused products left, that voucher is useless.
We want to buy everything, so the total cost without discounts is fixed:
Every voucher makes exactly one product free: the cheapest product inside that voucher's chosen group. So the real job is:
maximize the total price of free products.
Then the answer is simply:
Key Observation
A voucher with value needs exactly products. Among those , the cheapest one becomes free.
So if you want some product with price to be free using a voucher of size , you must also put other products with price at least in that same group. Otherwise would not be the cheapest.
That means a voucher of size is insane value: it gives one product for free immediately. A voucher of size needs one extra product. A voucher of size needs nine extra products just to make one product free. Bigger vouchers are more expensive to “feed”.
So we should use smaller vouchers earlier, while expensive products are still available.
Greedy Strategy
Sort prices in decreasing order:
Sort voucher sizes in increasing order:
Now process vouchers from smallest to largest.
For a voucher of size , take the next most expensive unused products. Since they are sorted decreasingly, inside this block:
the cheapest one is . That product becomes free, so we add it to freeSum, then move the pointer forward by .
If fewer than products remain, we cannot use that voucher, so we skip it. No magic, no loophole, no “maybe group it weirdly” nonsense. It needs exactly products.
Why This Greedy Works
Take any voucher of size . To make a product free, it must consume products total, and the free one is the cheapest among them.
For a fixed voucher size , if we are deciding which unused products to spend, using the most expensive remaining products gives the highest possible free product for that voucher, because the free product is the minimum of the chosen group. The best minimum you can get from any unused products is the -th most expensive unused product.
Now compare voucher sizes. Smaller vouchers consume fewer products per free item, so they should get priority on the expensive products. If a larger voucher is used before a smaller voucher, the larger voucher burns more expensive products just to create one free item. Swapping their order cannot make things worse: the smaller voucher can claim an expensive free item with fewer consumed products, leaving at least as much room for later vouchers.
So the optimal order is increasing , and each voucher takes the next block of most expensive unused products.
Algorithm
ptr = 0 and freeSum = 0.x:
ptr + x <= n, then a[ptr + x - 1] becomes free;freeSum;ptr += x.sum - freeSum.Complexity
Sorting dominates:
per test case, with total and bounded by , so this easily fits. Like, aggressively fits.
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void setIO() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
}
int main() {
setIO();
int t;
cin >> t;
while (t--) {
int n, k;
cin >> n >> k;
vector<ll> a(n);
ll total = 0;
for (ll &x : a) {
cin >> x;
total += x;
}
vector<int> b(k);
for (int &x : b) cin >> x;
sort(a.rbegin(), a.rend());
sort(b.begin(), b.end());
ll freeSum = 0;
int ptr = 0;
for (int x : b) {
if (ptr + x <= n) {
freeSum += a[ptr + x - 1];
ptr += x;
}
}
cout << total - freeSum << '\n';
}
return 0;
}#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void setIO() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
}
int main() {
setIO();
int t;
cin >> t;
while (t--) {
int n, k;
cin >> n >> k;
vector<ll> a(n);
ll total = 0;
for (ll &x : a) {
cin >> x;
total += x;
}
vector<int> b(k);
for (int &x : b) cin >> x;
sort(a.rbegin(), a.rend());
sort(b.begin(), b.end());
ll freeSum = 0;
int ptr = 0;
for (int x : b) {
if (ptr + x <= n) {
freeSum += a[ptr + x - 1];
ptr += x;
}
}
cout << total - freeSum << '\n';
}
return 0;
}