H. Take the Elevator
Solution
上行下行两个方向显然分开考虑,一次上下取两者需要移动距离的较大值。
考虑上行时,上升高度取决于最大的,因此考虑将大的先满足,在取满个最大的之后,考虑用大根堆维护已选乘客的最大值,接下来可以将的乘客加入(相当于有人在上电梯前下电梯),持续维护直到无法找到。
考虑下行时,上升高度取决于最大的,因此考虑将大的先满足,在取满个最大的之后,考虑用大根堆维护已选乘客的最大值,接下来可以将的乘客加入(相当于有人在下电梯后上电梯),持续维护直到无法找到。
对比两个方向,可以发现操作完全一致。
时间复杂度。
void solve(multiset<pair<int, int> > &st, int m) {
priority_queue<int>pq;
for (int i = 0; i < m && !st.empty(); ++i) {
pq.push((*st.rbegin()).second);
st.erase(st.lower_bound(*st.rbegin()));
}
while (!st.empty()) {
auto it = st.lower_bound(make_pair(pq.top() + 1, 0));
if (it == st.begin())break;
if (it == st.end())it = st.lower_bound(*st.rbegin());
else it = prev(it);
pq.pop();
pq.push(it -> second);
st.erase(it);
}
}
int main() {
int n = fast_IO::read(), m = fast_IO::read(), k = fast_IO::read();
multiset<pair<int, int> >up, down;
for (int i = 1; i <= n; ++i) {
int l = fast_IO::read(), r = fast_IO::read();
if (l < r) {
up.insert(make_pair(r, l));
}
else {
down.insert(make_pair(l, r));
}
}
ll ans = 0;
while (!up.empty() || !down.empty()) {
int ansup = 0, ansdown = 0;
if (!up.empty()) {
ansup = (*up.rbegin()).first - 1;
solve(up, m);
}
if (!down.empty()) {
ansdown = (*down.rbegin()).first - 1;
solve(down, m);
}
ans += max(ansup, ansdown) * 2;
}
printf("%lld", ans);
return 0;
}