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.
First kill a fake difficulty: you do not need to optimize several separate common gaps. If there are multiple openings, the doors between two neighboring openings can be slid to one side, merging those openings without decreasing total size.
So the answer is the maximum length of one common interval that every layer can leave empty.
For one layer, choose how many doors go to the left of the opening. If the first doors go left, shove them fully left; shove the rest fully right. Extremes are enough.
Let be the total length of the first doors and . Split gives this layer's possible clear interval: .
Now choose one interval from each layer to maximize their intersection. Sweep left endpoints in increasing order. Maintain the maximum chosen left endpoint and a multiset of current right endpoints; the current opening length is .
The statement says “total length of horizontal intervals,” which sounds like we may need to juggle a bunch of disconnected holes. Thankfully, no. That would be gross.
If there are two neighboring common openings with blocked junk between them, we can slide the doors sitting between those openings to one side. This merges the two openings and does not decrease their total open length. Repeat this until only one opening remains.
So we only need to maximize the length of one common interval.
One Layer
Take one layer with walls and door lengths
Let
with , and let be the total door length.
Suppose the final opening is some interval . In this layer, every door must be either completely left of the opening or completely right of it. Since doors cannot swap order, this is determined by a split index :
For a fixed split, the best thing is obvious: shove the left doors as far left as possible and shove the right doors as far right as possible. Then the largest empty interval created by this split is
Equivalently:
So each layer gives us candidate empty intervals, one for each split.
Global Reformulation
Now the problem is:
For every layer, choose one of its candidate intervals. Maximize the length of the intersection of all chosen intervals.
If the chosen interval for layer is , the common opening length is
If this is negative, it contributes .
For one layer, as increases, both endpoints increase:
This monotonicity is the whole trick.
Sweep
Start with split for every layer. That means every door is shoved to the right, and the current interval for a layer is
Maintain:
maxLeft: the maximum left endpoint among currently chosen intervals,Current answer candidate:
Now consider moving one more door of some layer to the left side. If we move door of a layer, that layer changes from split to split .
The new left endpoint becomes
and the right endpoint changes from
to
Create one event for each door with exactly those values. Sort events by the new left endpoint.
When processing all events with the same left endpoint:
maxLeft,Why The Sweep Is Correct
Fix some possible final left boundary .
For any layer, if another split has left endpoint at most , taking that later split can only increase that layer's right endpoint and will not increase the global left boundary past . So for this , the best state is: apply all moves whose new left endpoint is at most .
That is exactly what the sorted sweep represents. We check every coordinate where the state can change, so we don't miss the optimum.
Complexity
There is one event per door, so events.
Sorting them and doing multiset updates gives
Memory is linear. Clean enough; no cursed geometry needed.
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void setIO() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
}
struct Event {
ll left;
ll oldRight;
ll newRight;
};
int main() {
setIO();
int n;
cin >> n;
vector<Event> events;
multiset<ll> rights;
ll maxLeft = LLONG_MIN;
for (int i = 0; i < n; ++i) {
int k;
ll x1, x2;
cin >> k >> x1 >> x2;
vector<ll> pref(k + 1, 0);
for (int j = 1; j <= k; ++j) {
ll len;
cin >> len;
pref[j] = pref[j - 1] + len;
}
ll total = pref[k];
ll baseRight = x2 - total;
maxLeft = max(maxLeft, x1);
rights.insert(baseRight);
for (int j = 1; j <= k; ++j) {
events.push_back({x1 + pref[j], baseRight + pref[j - 1], baseRight + pref[j]});
}
}
sort(events.begin(), events.end(), [](const Event& a, const Event& b) {
return a.left < b.left;
});
ll ans = 0;
auto relax = [&]() {
ans = max(ans, *rights.begin() - maxLeft);
};
relax();
for (int i = 0; i < (int)events.size();) {
ll left = events[i].left;
while (i < (int)events.size() && events[i].left == left) {
auto it = rights.find(events[i].oldRight);
rights.erase(it);
rights.insert(events[i].newRight);
++i;
}
maxLeft = max(maxLeft, left);
relax();
}
cout << ans << '\n';
return 0;
}#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void setIO() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
}
struct Event {
ll left;
ll oldRight;
ll newRight;
};
int main() {
setIO();
int n;
cin >> n;
vector<Event> events;
multiset<ll> rights;
ll maxLeft = LLONG_MIN;
for (int i = 0; i < n; ++i) {
int k;
ll x1, x2;
cin >> k >> x1 >> x2;
vector<ll> pref(k + 1, 0);
for (int j = 1; j <= k; ++j) {
ll len;
cin >> len;
pref[j] = pref[j - 1] + len;
}
ll total = pref[k];
ll baseRight = x2 - total;
maxLeft = max(maxLeft, x1);
rights.insert(baseRight);
for (int j = 1; j <= k; ++j) {
events.push_back({x1 + pref[j], baseRight + pref[j - 1], baseRight + pref[j]});
}
}
sort(events.begin(), events.end(), [](const Event& a, const Event& b) {
return a.left < b.left;
});
ll ans = 0;
auto relax = [&]() {
ans = max(ans, *rights.begin() - maxLeft);
};
relax();
for (int i = 0; i < (int)events.size();) {
ll left = events[i].left;
while (i < (int)events.size() && events[i].left == left) {
auto it = rights.find(events[i].oldRight);
rights.erase(it);
rights.insert(events[i].newRight);
++i;
}
maxLeft = max(maxLeft, left);
relax();
}
cout << ans << '\n';
return 0;
}