记录--洛谷 P1190 [NOIP 2010 普及组] 接水问题
如果想查看完整题目,请前往P1190 [NOIP 2010 普及组] 接水问题](https://www.luogu.com.cn/problem/P1190)
P1190 [NOIP 2010 普及组] 接水问题
题目描述
学校里有一个水房,水房里一共装有 mmm 个龙头可供同学们打开水,每个龙头每秒钟的供水量相等,均为 111。
现在有 nnn 名同学准备接水,他们的初始接水顺序已经确定。将这些同学按接水顺序从 111 到 nnn 编号,iii 号同学的接水量为 wiw_iwi。接水开始时,111 到 mmm 号同学各占一个水龙头,并同时打开水龙头接水。当其中某名同学 jjj 完成其接水量要求 wjw_jwj 后,下一名排队等候接水的同学 kkk 马上接替 jjj 同学的位置开始接水。这个换人的过程是瞬间完成的,且没有任何水的浪费。即 jjj 同学第 xxx 秒结束时完成接水,则 kkk 同学第 x+1x+1x+1 秒立刻开始接水。若当前接水人数 n′n'n′ 不足 mmm,则只有 n′n'n′ 个龙头供水,其它 m−n′m - n'm−n′ 个龙头关闭。
现在给出 nnn 名同学的接水量,按照上述接水规则,问所有同学都接完水需要多少秒。
输入格式
第一行两个整数 nnn 和 mmm,用一个空格隔开,分别表示接水人数和龙头个数。
第二行 nnn 个整数 w1,w2,…,wnw_1,w_2,\ldots,w_nw1,w2,…,wn,每两个整数之间用一个空格隔开,wiw_iwi 表示 iii 号同学的接水量。
输出格式
一个整数,表示接水所需的总时间。
思路
贪心思路:
由于后面补位的同学的顺序不可改变,所以本题的思路就是将当前接水的同学中的最小值与后面补位的同学的时间相加,这样就有了一个新的接水时间temp,如果这个temp比原来的最大值mmax还要大,那么更新最大值mmax = temp,找到最后一个同学打完水。
我第一刻就想到这题有点类似于最小树的合并,将最小值取出,加上另一个数,再插回去,重新排序。所以我选用了以树结构为底层逻辑的multiset。
具体的实现代码如下。
C++完整代码
#include<bits/stdc++.h>
using namespace std;
int n, m;
typedef long long ll;
int arr[100005];
//multiset容器,内部按从小到大排序,可以用重复的元素
multiset<int> ms;
int mmax = 0;
int main() {
cin >> n >> m;
for(int i = 0;i < n;i++) {
cin >> arr[i];
}
for(int i =0 ;i < m;i++) {
if(arr[i] > mmax) {mmax = arr[i];}//找到前m个接水量的最大值
ms.insert(arr[i]);
}
for(int i = m;i< n;i++) {
//模拟目前一个最快接完水的同学在接上下一个同学,这样他们接水的时间相加就是一个新的打水时间,
//与最大值比较,如果更大,就更新最大值
int temp = *ms.begin() + arr[i];
if(temp > mmax) {//更新最大值
mmax = temp;
}
ms.erase(ms.begin());//删除ms中最小的元素,因为它已经变成了新的打水时间temp的一部分。
ms.insert(temp);//将temp插入,因为它也可能是最小的打水时间。
}
cout << mmax << endl;//mmax就是答案。
return 0;
}
更多推荐



所有评论(0)