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.
Split the monsters by whether . A monster gives you nothing, so fighting it early can only remove a sword you might still need later.
For , the number of swords stays the same and the used sword's damage never decreases because it becomes . So if such a monster is killable, killing it is always safe.
When killing a monster, use the weakest sword with damage at least . If a weaker eligible sword can do the job, using a stronger one is just wasting upgrade potential. Classic Codeforces tax for being flashy.
Sort all monsters by . Maintain sword damages in a multiset; for each monster, take lower_bound(b_i), replace that sword with , and count the kill.
After all positive monsters are processed, handle monsters sorted by . Again use the weakest sword that can kill each one, but now erase it permanently. Positive kills plus these consumed kills is the answer.
The Important Split
There are two completely different monster types:
That second type is a trap if you do it early. Since a monster never helps future fights, we can always move all those fights to the end. Keeping extra swords around during the upgrade phase can only help.
So the plan is:
One subtle point: does not mean the sword necessarily gets stronger. If , the sword stays at . But it still comes back, and that is the part that matters.
Greedy For Returning-Sword Monsters
Consider only monsters with .
Sort them by increasing required life .
For each monster, we want some sword with damage at least . Among all valid swords, choose the weakest one.
Why weakest?
Suppose two eligible swords have damages . If we use , the pair becomes:
If we use , the pair becomes:
Using the weaker sword is never worse. If is small, nothing important changes. If is medium, the weak sword gets upgraded while the strong sword stays available. If is huge, upgrading the weak sword is obviously better because the strong sword remains strong too.
So the correct move is: use the weakest sword that can kill the monster.
A multiset gives exactly this with lower_bound(b_i).
If no sword can kill the current positive monster, then no later positive monster can be newly unlocked by it, because we sorted by and later requirements are at least as large. So the greedy process is done for positive monsters.
Each successful positive fight adds to the answer and replaces sword damage by .
Then Spend The Swords
Now handle monsters with .
These consume swords, so this is just matching swords to requirements. Sort these monsters by increasing , and for each one use the weakest sword that can kill it.
Again, this is the standard greedy: do the easiest remaining monster with the smallest usable sword, saving bigger swords for bigger problems.
Algorithm
For each test case:
Complexity is per test case, which fits easily because the total input size is .
#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, m;
cin >> n >> m;
multiset<ll> swords;
for (int i = 0; i < n; i++) {
ll x;
cin >> x;
swords.insert(x);
}
vector<ll> b(m), c(m);
for (ll &x : b) cin >> x;
for (ll &x : c) cin >> x;
vector<pair<ll, ll>> positive;
vector<ll> consuming;
for (int i = 0; i < m; i++) {
if (c[i] > 0) positive.push_back({b[i], c[i]});
else consuming.push_back(b[i]);
}
sort(positive.begin(), positive.end());
sort(consuming.begin(), consuming.end());
int ans = 0;
for (auto [need, gain] : positive) {
auto it = swords.lower_bound(need);
if (it == swords.end()) break;
ll x = *it;
swords.erase(it);
swords.insert(max(x, gain));
ans++;
}
for (ll need : consuming) {
auto it = swords.lower_bound(need);
if (it == swords.end()) break;
swords.erase(it);
ans++;
}
cout << ans << '\n';
}
}#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, m;
cin >> n >> m;
multiset<ll> swords;
for (int i = 0; i < n; i++) {
ll x;
cin >> x;
swords.insert(x);
}
vector<ll> b(m), c(m);
for (ll &x : b) cin >> x;
for (ll &x : c) cin >> x;
vector<pair<ll, ll>> positive;
vector<ll> consuming;
for (int i = 0; i < m; i++) {
if (c[i] > 0) positive.push_back({b[i], c[i]});
else consuming.push_back(b[i]);
}
sort(positive.begin(), positive.end());
sort(consuming.begin(), consuming.end());
int ans = 0;
for (auto [need, gain] : positive) {
auto it = swords.lower_bound(need);
if (it == swords.end()) break;
ll x = *it;
swords.erase(it);
swords.insert(max(x, gain));
ans++;
}
for (ll need : consuming) {
auto it = swords.lower_bound(need);
if (it == swords.end()) break;
swords.erase(it);
ans++;
}
cout << ans << '\n';
}
}