每个龙头完工时刻等于分给它的人的水量之和,故用最小堆维护各龙头累计接水量,新人接到最早空出的龙头,O(n log m)。
OJ: roj
题目 ID: 1233
难度:普及-
标签:模拟贪心优先队列python
创建: 2026-09-30 00:57
更新: 2026-10-05 06:12
题目描述
水房里有
输入:第 1 行两个整数
输出:一行一个整数,表示接水所需的总时间(秒)。
样例 1:5 3,4 4 1 2 1 → 输出 4。样例 2:8 4,23 71 87 32 70 93 80 76 → 输出 163。
思路
由于完成即换人,龙头不空转,每个龙头的完工时刻就是分给它的
参考代码
Python 版:
python
#!/usr/bin/env python3
# Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
# rbook: -> https://rbook.roj.ac.cn https://rbook2.roj.ac.cn
# rainboy的学习导航网站: https://idx.roj.ac.cn
# create_at: 2026-09-30 00:57
# update_at: 2026-09-30 01:04
import sys
from collections.abc import Iterable
from heapq import heapify, heapreplace
def finish_time(loads: list[int], taps: int) -> int:
"""返回所有人接完水的总秒数。
规则等价于:新人补到"累计接水量最小"的龙头(它最先空出来,其它龙头都还在忙)。
题面直接规定了落点,没有需要搜索的目标;龙头不空转,所以每个龙头的完工时刻就是
分给它的 w 之和,答案取这些累计量的最大值。堆里存的就是各龙头的累计接水量。
"""
earliest = loads[:taps] # 前 taps 个人先各占一个龙头;n < m 时堆自然更小
heapify(earliest)
for load in loads[taps:]:
heapreplace(earliest, earliest[0] + load) # 最早空出的龙头立刻接这位同学
return max(earliest, default=0)
def solve() -> None:
"""读入 n、m 和 n 个接水量,输出总接水时间。"""
data: Iterable[bytes] = iter(sys.stdin.buffer.read().split())
n, m = int(next(data)), int(next(data))
loads = [int(next(data)) for _ in range(n)]
print(finish_time(loads, m))
if __name__ == "__main__":
solve()C++ 版(同一算法):
cpp
/**
* Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
* rbook: -> https://rbook.roj.ac.cn https://rbook2.roj.ac.cn
* rainboy的学习导航网站: https://idx.roj.ac.cn
* create_at: 2026-10-05 06:12
* update_at: 2026-10-05 06:12
*/
// main.cpp:接水问题,用最小堆维护各龙头累计接水量。
#include <cstdio>
#include <queue>
#include <vector>
using namespace std;
typedef long long ll;
// 小根堆:存放每个正在供水的龙头的累计接水量,堆顶就是最早空出来的龙头
priority_queue<ll, vector<ll>, greater<ll> > loads;
int main() {
ll n, m;
scanf("%lld %lld", &n, &m);
ll ans = 0;
for (ll i = 1; i <= n; i++) {
ll w;
scanf("%lld", &w);
if (i <= m) {
// 开始时前 m 名同学各占一个龙头(n < m 时只占 n 个龙头)
loads.push(w);
} else {
// 队首同学接到"最早空出的龙头"上:换掉堆顶的累计量
ll t = loads.top();
loads.pop();
loads.push(t + w);
}
}
// 龙头不空转,总时间就是各龙头累计接水量的最大值
while (!loads.empty()) {
ans = max(ans, loads.top());
loads.pop();
}
printf("%lld\n", ans);
return 0;
}