/*******************************************************
1) InMobi OA — Minimum Active Towers in a Circle
Problem:
- n towers in a circle (0..n-1)
- activate i => neutralizes all towers within circular distance R[i] (including itself)
- find minimum activations to neutralize all towers
Idea:
- Convert each tower to a coverage interval on the circle
- Unroll circle to a line of length 2n
- Then solve "minimum intervals to cover a segment of length n"
- Greedy "extend farthest" + binary lifting (jump pointers) for speed
Time: O(n log n)
*******************************************************/
#include <bits/stdc++.h> // include almost all standard C++ headers (common in CP)
using namespace std; // avoid writing std:: everywhere
int main() { // program starts here
ios::sync_with_stdio(false); // faster I/O
cin.tie(nullptr); // faster I/O
int n; // number of towers
cin >> n; // read n
vector<long long> R(n); // R[i] = radius for tower i (use long long for safety)
for (int i = 0; i < n; i++) cin >> R[i]; // read all radii
// If any tower covers the whole circle by itself, answer is 1.
for (int i = 0; i < n; i++) { // loop all towers
if (2LL * R[i] + 1 >= n) { // coverage size in circle is (2*R+1); if >= n => covers all
cout << 1 << "\n"; // print 1 activation
return 0; // exit early
}
}
int P = 2 * n; // total "unrolled" positions: 0..2n-1 (we call that P)
int LAST = P - 1; // last valid index in unrolled range is 2n-1
vector<int> bestAtL(P, -1); // bestAtL[l] = farthest right endpoint among intervals starting at l
auto norm = [&](long long x) -> int { // function to wrap any integer x into [0..n-1]
x %= n; // take modulo n
if (x < 0) x += n; // if negative, shift into positive range
return (int)x; // return as int
};
// Build intervals for each tower i.
for (int i = 0; i < n; i++) { // go through each tower
long long rad = R[i]; // radius of coverage
long long rawL = (long long)i - rad; // left boundary (may be negative)
long long rawR = (long long)i + rad; // right boundary (may exceed n-1)
int L = norm(rawL); // normalize left into [0..n-1]
int RR = norm(rawR); // normalize right into [0..n-1]
// helper to add an interval [l, r] to bestAtL (clamped to our unrolled array)
auto addInterval = [&](long long l, long long r) { // lambda function for adding interval
if (l > LAST) return; // if start is beyond useful range, ignore
if (l < 0) return; // safety check (shouldn't happen here)
r = min<long long>(r, LAST); // clamp r to LAST so we don't go beyond array
bestAtL[(int)l] = max(bestAtL[(int)l], (int)r); // keep only farthest reach for that start l
};
if (L <= RR) { // case 1: interval does NOT wrap around circle
addInterval(L, RR); // add interval in base copy [0..n-1]
addInterval((long long)L + n, (long long)RR + n); // add same interval shifted by +n for unrolled copy
} else { // case 2: interval wraps around (covers end and start of circle)
addInterval(L, (long long)RR + n); // represent wrap as one continuous interval in unrolled line
addInterval((long long)L + n, (long long)RR + 2LL * n); // second copy shifted by +n again
}
}
vector<int> farthest(P, -1); // farthest[x] = best reach among all intervals with start <= x
for (int x = 0; x < P; x++) { // build prefix maximum
farthest[x] = bestAtL[x]; // start with interval that starts exactly at x
if (x) farthest[x] = max(farthest[x], farthest[x - 1]); // also consider earlier starts (prefix max)
}
vector<int> nxt(P + 1, P); // nxt[x] = next uncovered position after taking 1 greedy step
for (int x = 0; x < P; x++) { // compute nxt for each x
if (farthest[x] < x) nxt[x] = x; // if we cannot even cover x, we're stuck (no progress)
else nxt[x] = farthest[x] + 1; // else jump to one past farthest covered point
}
nxt[P] = P; // if already at end, stay at end
int LOG = 1; // number of levels for binary lifting
while ((1 << LOG) <= P + 1) LOG++; // increase LOG until 2^LOG is big enough
vector<vector<int>> up(LOG, vector<int>(P + 1, P)); // up[j][x] = position after 2^j greedy steps
up[0] = nxt; // base case: 2^0 = 1 step is nxt
for (int j = 1; j < LOG; j++) { // build higher jumps
for (int x = 0; x <= P; x++) { // for every position
up[j][x] = up[j - 1][ up[j - 1][x] ]; // jump twice using previous layer
}
}
const int INF = 1e9; // a large number for "min answer"
int ans = INF; // store best answer
// Try starting segment at each s in [0..n-1] covering [s, s+n-1]
for (int s = 0; s < n; s++) { // try each start
int target = s + n; // we want to reach at least this position (one past end)
if (nxt[s] == s) continue; // if stuck at start, skip
int pos = s; // current position we need to cover
int steps = 0; // number of activations used
// Use binary lifting to take big jumps while still not reaching target
for (int j = LOG - 1; j >= 0; j--) { // from largest jump down to smallest
if (up[j][pos] < target) { // if taking 2^j steps still keeps us before target
pos = up[j][pos]; // apply the jump
steps += (1 << j); // add number of steps taken
}
}
if (nxt[pos] == pos) continue; // if we are stuck before finishing, skip
steps++; // take one more greedy step
pos = nxt[pos]; // update position
if (pos >= target) ans = min(ans, steps); // if covered full segment, update answer
}
cout << (ans == INF ? -1 : ans) << "\n"; // print answer (or -1 if impossible)
return 0; // exit
}