E - フェンスの塗装 / Painting the Fence Editorial by admin
Claude 4.6 Opus (Thinking)Overview
A problem to maximize the number of painted boards when skipping \(K\) consecutive intervals out of \(M\) intervals. We solve this by minimizing the “loss from skipping” relative to the union of all intervals.
Analysis
Basic Approach: Subtract Loss from Total
Let totalUnion be the number of painted boards when all \(M\) instructions are executed (the size of the union of all intervals). If we define \(\text{loss}(s)\) as the “loss” when choosing skip start position \(s\), the answer is:
\[\max_{s} (\text{totalUnion} - \text{loss}(s)) = \text{totalUnion} - \min_{s} \text{loss}(s)\]
Meaning of Loss
A segment (contiguous range of boards) becomes a “loss” only when all instructions that paint that segment are entirely contained within the skip range \([s, s+K-1]\).
Per-Segment Analysis
For each segment after coordinate compression, among the instructions that cover that segment: - Let minimum index be \(\text{min\_idx}\) - Let maximum index be \(\text{max\_idx}\)
The condition for this segment to become a loss is: $\(s \leq \text{min\_idx} \quad \text{and} \quad s + K - 1 \geq \text{max\_idx}\)$
Rearranging, the range of \(s\) is \([\text{max\_idx} - K + 1,\ \text{min\_idx}]\).
Problem with Naive Solution
Naively computing the loss for each \(s\) takes \(O(M \cdot N)\) and results in TLE. However, using a difference array, we can record each segment’s contribution in \(O(1)\) and compute everything at the end.
Algorithm
Coordinate Compression: Treat each interval \([L_i, R_i]\) as a half-open interval \([L_i, R_i+1)\), collect boundary values, sort and deduplicate them. This divides the number line into at most \(2M\) segments.
Sweep Line: Scan the coordinate-compressed segments from left to right. For each segment, maintain the active instruction set (the set of instruction indices that cover that segment) using a
multiset.Record Loss with Difference Array: For each segment, compute the range \([lo, hi]\) of \(s\) values where loss occurs from the minimum and maximum indices of the active set, and add the segment length to the difference array.
Compute Minimum Loss: Compute the prefix sum of the difference array to recover \(\text{loss}(s)\) for each \(s\), and find the minimum value.
Answer: \(\text{totalUnion} - \min_s \text{loss}(s)\)
Complexity
- Time complexity: \(O(M \log M)\) (sorting for coordinate compression, multiset operations each take \(O(\log M)\) for a total of \(O(M)\) times)
- Space complexity: \(O(M)\) (storage for coordinates, events, and difference array)
Implementation Notes
Coordinate Compression: Essential since \(N\) can be up to \(10^9\). Using half-open intervals \([L_i, R_i+1)\) makes handling easier.
Event Sorting: Sort by
(coordinate, type, index)tuples so that end events (type=0) are processed before start events (type=1) at the same coordinate.1-indexed vs 0-indexed Conversion: In the code, indices are managed as 0-indexed and converted to 1-indexed when computing the difference array.
Case \(lo > hi\): This segment will not become a loss regardless of which \(s\) is chosen (the skip range of \(K\) instructions cannot contain all covering instructions). Skip this case.
Use of
long long: Since \(N\) can be large, care must be taken to avoid overflow in the painted board count.Source Code
#include <bits/stdc++.h>
using namespace std;
int main() {
ios_base::sync_with_stdio(false);
cin.tie(NULL);
long long N;
int M, K;
cin >> N >> M >> K;
vector<int> L(M), R(M);
for (int i = 0; i < M; i++) {
cin >> L[i] >> R[i];
}
// Collect coordinate boundaries (half-open intervals [L_i, R_i+1))
vector<int> coords;
for (int i = 0; i < M; i++) {
coords.push_back(L[i]);
coords.push_back(R[i] + 1);
}
sort(coords.begin(), coords.end());
coords.erase(unique(coords.begin(), coords.end()), coords.end());
// Events: (position, type, index) - type 0 = end, type 1 = start
vector<tuple<int, int, int>> evts;
for (int i = 0; i < M; i++) {
evts.push_back({L[i], 1, i});
evts.push_back({R[i] + 1, 0, i});
}
sort(evts.begin(), evts.end());
multiset<int> active;
long long totalUnion = 0;
int evt_idx = 0;
// Difference array for loss(s), s from 1 to M-K+1
vector<long long> diff(M + 3, 0);
for (int c = 0; c + 1 < (int)coords.size(); c++) {
int left = coords[c];
int right = coords[c + 1];
long long len = (long long)(right - left);
// Process all events at position 'left'
// End events (type 0) come before start events (type 1) due to sorting
while (evt_idx < (int)evts.size() && get<0>(evts[evt_idx]) == left) {
auto [pos, type, idx] = evts[evt_idx];
if (type == 1) active.insert(idx);
else active.erase(active.find(idx));
evt_idx++;
}
if (!active.empty()) {
totalUnion += len;
int min_idx = *active.begin() + 1; // 1-indexed
int max_idx = *active.rbegin() + 1; // 1-indexed
// This segment is lost when s in [max_idx - K + 1, min_idx]
// intersected with [1, M - K + 1]
int lo = max(1, max_idx - K + 1);
int hi = min(M - K + 1, min_idx);
if (lo <= hi) {
diff[lo] += len;
diff[hi + 1] -= len;
}
}
}
// Find minimum loss
long long minLoss = LLONG_MAX;
long long current = 0;
for (int s = 1; s <= M - K + 1; s++) {
current += diff[s];
minLoss = min(minLoss, current);
}
cout << totalUnion - minLoss << endl;
return 0;
}
This editorial was generated by claude4.6opus-thinking.
posted:
last update: