Many Div. 2 A–C and some Div. 1 problems ask for “the minimum number of operations”, and the answer is always in a set like or . The method:
- Find a universal strategy that always works in operations (often “apply the operation to the whole array” a couple of times).
- Characterize exactly when operations suffice. Each characterization is usually a simple scan.
- Prove the lower bounds: when the cheaper checks fail, fewer operations are impossible.
The brute-force table from Observation Toolkit shows the bounded answer at once.
Example 1: sorting by rearranging proper subarrays
Operation: choose a subarray that is not the whole array and rearrange it arbitrarily. Minimum operations to sort a permutation of ():
int permutationSort(const vector<int>& p) { // rearrange any proper subarray; values 1..n
int n = sz(p);
if (is_sorted(all(p))) return 0;
if (p[0] == 1 || p[n - 1] == n) return 1;
if (p[0] == n && p[n - 1] == 1) return 3;
return 2;
}Proof: the answer is 0, 1, 2 or 3 exactly as coded
If , sort in one operation; symmetrically if . Otherwise one operation cannot work: a proper subarray misses position or position , and the element there is wrong. Two operations work whenever : sort positions (this brings to the front, because is among them), then sort positions . Symmetrically, two work whenever . The case , : sorting positions moves away from the front, and then two more operations finish, so three suffice. Two do not: after any first operation, is still at position or is still at position ; then neither nor holds, so one more operation cannot sort. Verified by BFS over all permutations for .
Example 2: make everything zero with mex
Operation: choose and set every () to . Minimum operations to make the array all zeros:
int mexToZero(const vector<int>& a) { // set a[l..r] := mex(a[l..r]); make everything 0
int l = 0, r = sz(a) - 1;
while (l <= r && a[l] == 0) l++;
while (r >= l && a[r] == 0) r--;
if (l > r) return 0;
for (int i = l; i <= r; i++) if (a[i] == 0) return 2;
return 1;
}Proof: 0 if all zero, 1 if the nonzeros form one block, else 2
If the nonzero elements form one contiguous block, applying the operation to that block gives mex (no zero inside), so one operation suffices. One operation must cover every nonzero element, so its segment contains the block hull; if a zero lies inside the hull, the mex is positive and the segment becomes nonzero. Two operations always suffice: apply it to the whole array, getting a constant ; if , apply it again, and the mex of an array of ‘s is . Verified by BFS over all arrays of length with values in .
Where small answers hide
| Signal | Universal strategy |
|---|---|
| ”operation on any subarray / substring” | apply to the whole thing, or to a prefix plus a suffix |
| ”minimum number of operations” with a case | an invariant decides ; otherwise the answer is or |
| operations with mex, gcd, or, and | applying to everything collapses the array to a constant |
| ”make the array good” where good is a local condition | fix one end, then the other |
Related: Proof Techniques.