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.
The number of move turns is fixed: exactly . So the whole problem is really: what is the minimum number of rests?
A rest resets the consecutive-move counter. So the path becomes several blocks of consecutive moves. A block of length costs
health total, and Nezuko must still have positive health after the block.
If you decide that the longest block length will be at most , then the best strategy is to split the moves into as few blocks as possible: blocks of size , except maybe one smaller block. More blocks means more rests, so bigger is good for rest count.
For a fixed cap , the total health spent by the moves is minimized by making the blocks as full as possible: if , the total movement damage is
If this damage is already less than , no extra healing beyond the mandatory rests between blocks is needed.
For fixed , the number of rests needed is
The first term is the number of resets between blocks; the second is the healing needed so final health stays positive. Minimize this over . The function is nicely unimodal-ish, so ternary search on plus checking nearby values works.
Let’s strip away the anime fog and look at the actual machine.
Nezuko must move exactly times. That part is non-negotiable. The only thing we can optimize is how many times she rests. Therefore:
A rest does two things:
That second part is the entire problem.
Blocks of moves
Any valid plan can be seen as blocks of consecutive moves, separated by rests.
A block of length costs
health. Since health only decreases inside a block, it is enough to require that after the whole block the health is still positive.
So if block lengths are , total movement damage is
The number of mandatory rests between those blocks is .
Fix the maximum block length
Suppose no block is longer than .
Then the minimum possible number of blocks is
so we need at least
rests just to reset between blocks.
If
then using chunks of length , plus one leftover chunk of length , gives movement damage
For this , the rests must cover two constraints:
so
Therefore
The answer is
Why searching works
As grows:
So we can ternary search over integer . Since integer ceilings make the function jumpy, don’t be cute: ternary search until the interval is small, then brute force every remaining .
For each :
Then print .
Use long long; intermediate values fit. No Big Integer nonsense, thankfully.
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void setIO() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
}
static ll tri(ll x) {
return x * (x + 1) / 2;
}
static ll need(ll h, ll d, ll x) {
ll q = d / x;
ll r = d % x;
ll damage = q * tri(x) + tri(r);
ll blocks = (d + x - 1) / x;
ll resetRests = blocks - 1;
ll healRests = damage - h + 1;
return max(resetRests, healRests);
}
int main() {
setIO();
int t;
cin >> t;
while (t--) {
ll h, d;
cin >> h >> d;
ll l = 1, r = d;
while (r - l > 5) {
ll m1 = l + (r - l) / 3;
ll m2 = r - (r - l) / 3;
if (need(h, d, m1) <= need(h, d, m2)) {
r = m2 - 1;
} else {
l = m1 + 1;
}
}
ll best = LLONG_MAX;
for (ll x = l; x <= r; x++) {
best = min(best, need(h, d, x));
}
cout << d + best << '\n';
}
return 0;
}#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void setIO() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
}
static ll tri(ll x) {
return x * (x + 1) / 2;
}
static ll need(ll h, ll d, ll x) {
ll q = d / x;
ll r = d % x;
ll damage = q * tri(x) + tri(r);
ll blocks = (d + x - 1) / x;
ll resetRests = blocks - 1;
ll healRests = damage - h + 1;
return max(resetRests, healRests);
}
int main() {
setIO();
int t;
cin >> t;
while (t--) {
ll h, d;
cin >> h >> d;
ll l = 1, r = d;
while (r - l > 5) {
ll m1 = l + (r - l) / 3;
ll m2 = r - (r - l) / 3;
if (need(h, d, m1) <= need(h, d, m2)) {
r = m2 - 1;
} else {
l = m1 + 1;
}
}
ll best = LLONG_MAX;
for (ll x = l; x <= r; x++) {
best = min(best, need(h, d, x));
}
cout << d + best << '\n';
}
return 0;
}