3377 [Mz]接水问题2
时间限制: 1 s
空间限制: 64000 KB
题目等级 : 钻石 Diamond
题解
查看运行结果
题目描述 Description
学校里有一个水房,水房里一共装有m个龙头可供同学们打开水,每个龙头每秒钟的供水量相等,均为1。
现在有n名同学准备接水,他们的初始接水顺序已经确定。将这些同学按接水顺序从 1到n编号,i号同学的接水量为wi。接水开始时,1到m号同学各占一个水龙头,并同时打开水龙头接水。当其中某名同学j完成其接水量要求wj后,下一名排队等候接水的同学k马上接替j同学的位置开始接水。这个换人的过程是瞬间完成的,且没有任何水的浪费。即j同学第x秒结束时完成接水,则k同学第x+1秒立刻开始接水。若当前接水人数n’不足m,则只有n’个龙头供水,其它m-n’个龙头关闭。
现在给出n名同学的接水量,按照上述接水规则,问所有同学都接完水需要多少秒。
特别地,同学们在打水前排好了队,接水所用时间更长的先接。
(ps:出题人本来想设计一个贪心的题目,然后发现用贪心做有反例,只能强改题目,在此声明道歉。不要在意样例解释。)
输入描述 Input Description
第 1 行2 个整数 n 和 m,用一个空格隔开,分别表示接水人数和龙头个数。
第 2 行 n 个整数 w1、w2、„„、wn,每两个整数之间用一个空格隔开,wi表示 i 号同学的接水量。
输出描述 Output Description
输出只有一行,1 个整数,表示接水所需的总时间。
样例输入 Sample Input
5 3
4 4 1 2 1
样例输出 Sample Output
4
思路:
模拟性质的堆
先排序,从大到小
然后把前m个丢进堆里
每次取出最小的,加上正在排队的最大的,丢回去
随手维护max
输出max
小技巧:
随手维护max,可以省去最后一步把堆里的数都丢出来取最大;
stl的优先队列是 priority_queue< xxx > (可以用搜狗输入法打哦)
重定义小根堆 priority_queue<类型,vector<类型>,greater<类型> > (注意最后一个空格)
//优先队列版
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;
int n,m,num[1000050],tot,maxx;
priority_queue<int,vector<int>,greater<int> > Q;
bool cmp(int a,int b){
return a>b;
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%d",&num[i]);
sort(num+1,num+n+1,cmp);
maxx=num[1];
for(tot=0;tot<m;++tot){
Q.push(num[tot+1]);
}
while(tot<=n){
int v=Q.top();
Q.pop();
v+=num[++tot];
if(v>maxx) maxx=v;
Q.push(v);
}
printf("%d",maxx);
return 0;
}
//手打堆版
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=1000050ll;
int n,m,num[maxn],d[maxn],maxx;
void inswap(int a,int b){
int tmp=d[a];
d[a]=d[b];
d[b]=tmp;
return ;
}
void inpop(){
inswap(1,m);
d[m]=0;
m--;
bool bo=1;
int now=1;
int minn;
while(bo&&d[now*2]!=0){
if(d[now]>d[now*2])
minn=now*2;
else minn=now;
if(d[minn]>d[now*2+1]&&d[now*2+1])
minn=now*2+1;
if(minn==now) {
break;
bo=0;
}
else {
inswap(now,minn);
now=minn;
}
}
return ;
}
void inpush(int x){
m++;
d[m]=x;
bool bo=1;
int now=m;
while(bo){
if(d[now]<d[now/2]){
inswap(now,now/2);
now=(now/2);
}
else{
break;
bo=0;
}
}
return ;
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%d",&num[i]);
sort(num+1,num+n+1);
int tot=n-m;
for(int i=1;i<=m;i++)
d[i]=num[tot+i];
while(tot){
int a=d[1];
inpop();
a=a+num[tot];tot--;
inpush(a);
}
for(int i=1;i<=m;i++)
maxx=max(maxx,d[i]);
printf("%d",maxx);
return 0;
}