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.
A monotone route can only dodge a circular blocked region by using one of two border corridors: left+top, or bottom+right.
So the disk must touch both opposite boundary chains. Touching left/top means or ; touching bottom/right means or .
If either chain is missed, a border-hugging path avoids the jammer completely. If both chains are touched, the disk forms a separating wall.
After the wall conditions, separately exclude centers whose disk contains or . For fixed , those exclusions become square-root bounds on .
Swap so the loop is over the smaller dimension. For each fixed , compute one interval of valid values using integer square roots, then add .
Research first: the canonical statement is the Codeforces problem page: https://codeforces.com/contest/2199/problem/G. The official Kotlin Heroes 14 editorial page lists 2199G - Jammer and includes adedalic's official solution, although the tutorial text itself is still loading: https://codeforces.com/blog/entry/151783. The official code uses the same dimension-swap plus integer-square-root interval counting derived here.
Let the jammer be centered at , and let be its radius- disk.
The key observation is that catches every monotone path iff it touches both opposite boundary chains:
In formulas, those are
and
Why necessary? If the disk misses the upper-left chain, the robot can go straight up along the left border and then right along the top border, avoiding the jammer. If it misses the lower-right chain, the robot can go right along the bottom border and then up along the right border. So missing either chain means the jammer is not guaranteed to work.
Why sufficient? A connected disk touching both chains separates the southwest corner from the northeast corner inside the rectangle. Any monotone route must cross it. Also, this is still valid for the statement's lattice-point interception: every robot move is a unit horizontal/vertical segment between integer points, and the center is integer. For such a unit segment, if it intersects the disk, one endpoint is inside the disk too. So every route has some integer path point within distance .
Now apply the stealth constraints:
The problem is symmetric under swapping axes, so assume after swapping if needed. Then loop over . This is fine because , so the smaller side is small enough.
For a fixed , all valid values form one interval .
Lower bound:
If , the disk already touches the left side, so the upper-left wall condition is satisfied. We only need to avoid covering the start:
Therefore
If , the start is automatically safe, but the disk must touch the top side:
Upper bound:
If , the disk already touches the right side, so the lower-right wall condition is satisfied. We only need to avoid covering the finish:
Thus
If , the finish is automatically safe, but the disk must touch the bottom side:
For this fixed , contribute
Use a corrected integer square root. Raw floating point is how you donate a WA to the judge for no reason.
Complexity: time and memory.
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void setIO() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
}
ll isqrt(ll v) {
ll x = sqrt((long double)v);
while ((__int128)(x + 1) * (x + 1) <= v) ++x;
while ((__int128)x * x > v) --x;
return x;
}
int main() {
setIO();
int t;
cin >> t;
while (t--) {
ll n, m, r;
cin >> n >> m >> r;
if (n > m) swap(n, m);
ll ans = 0;
ll rr = r * r;
for (ll x = 0; x <= n; ++x) {
ll low, high;
if (x <= r) {
low = isqrt(rr - x * x) + 1;
} else {
low = max(0LL, m - r);
}
ll dx = n - x;
if (dx <= r) {
high = m - 1 - isqrt(rr - dx * dx);
} else {
high = min(m, r);
}
if (low <= high) ans += high - low + 1;
}
cout << ans << '\n';
}
}#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void setIO() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
}
ll isqrt(ll v) {
ll x = sqrt((long double)v);
while ((__int128)(x + 1) * (x + 1) <= v) ++x;
while ((__int128)x * x > v) --x;
return x;
}
int main() {
setIO();
int t;
cin >> t;
while (t--) {
ll n, m, r;
cin >> n >> m >> r;
if (n > m) swap(n, m);
ll ans = 0;
ll rr = r * r;
for (ll x = 0; x <= n; ++x) {
ll low, high;
if (x <= r) {
low = isqrt(rr - x * x) + 1;
} else {
low = max(0LL, m - r);
}
ll dx = n - x;
if (dx <= r) {
high = m - 1 - isqrt(rr - dx * dx);
} else {
high = min(m, r);
}
if (low <= high) ans += high - low + 1;
}
cout << ans << '\n';
}
}