H
贪心
题意
贴的题解中的题意,这里其实写错了,楼高
k
k
k, 载客量限制为
m
m
m 。
思路
因为下降的过程中间不能转换方向,而上行的人肯定乘坐上行时的电梯,下行的人一定乘坐下行时的电梯(废话),所以不妨将人分为上行和下行两个方向来考虑。可以发现这两者是类似的,下面先考虑上行的人。
先考虑简单的情况:在每次上升的途中至多乘坐 m m m 人。而电梯的运行时间显然只和到达楼层最高的那个人有关,因此,在这种情况下我们每次贪心地选到达高度前 m m m 高的人乘坐电梯是最优解。
在此基础上,需要在每次上升的途中乘坐尽可能多的人。因此只要从上到下按终点高度尽可能地时时刻刻选 m m m 个人即可。
具体而言,我们可以记录每个上行的人的起始位置 s t st st 和终点位置 e d ed ed,利用前缀和维护当前电梯里有多少个人,如果超过 m m m 人则需要乘坐下一趟电梯,在这个过程中记录一共需要多少趟上行电梯以及它们需要到达的最高楼层。下行同理,具体见代码。
代码
int n, m, k;
struct Node {
int pos, d; //pos表示位置,d=1表示上电梯 d=-1表示下电梯
bool operator < (const Node &x) const {
if(pos != x.pos) return pos > x.pos;
return d < x.d;
}
};
vector<Node> up, down;
void solve() {
cin >> n >> m >> k;
for(int i = 1; i <= n; i++) {
int st, ed;
cin >> st >> ed;
if(st < ed) {
up.pb({st, -1});
up.pb({ed, 1});
}
else {
down.pb({st, 1});
down.pb({ed, -1});
}
}
sort(up.begin(), up.end());
sort(down.begin(), down.end());
int cnt = 0;
vector<int> up_max, down_max; //表示每次上升/下降到达的最大高度,size()表示次数
for(auto x : up) {
cnt += x.d; //维护当前电梯里的人数,如果超过则需要等下一次电梯
if(cnt > up_max.size() * m) up_max.pb(x.pos);
}
for(auto x : down) {
cnt += x.d;
if(cnt > down_max.size() * m) down_max.pb(x.pos);
}
int mx = max(up_max.size(), down_max.size());//总往返次数,为单程中的最大值。
int ans = 0;
for(int i = 0; i < mx; i++) {
cnt = 0;
if(up_max.size() > i) {
chmax(cnt, up_max[i]);
}
if(down_max.size() > i) {
chmax(cnt, down_max[i]);
}
ans = ans + (cnt-1) * 2;
}
cout << ans << endl;
}