2021牛客暑期多校训练营6
F
题意:
n份汉堡肉,m口锅,第i份汉堡肉烤熟需要时间 ,每份汉堡肉至多可以分成两次烤熟,即 ,任意时刻一口锅里至多烤一份汉堡肉,问烤熟所有汉堡肉需要的最小时间是多少并且输出每一份汉堡肉在几口锅中烤和烤的时刻(若有两口锅,按时间先后排列)。
注意,这个时间指的是所有汉堡肉在这一时刻都已经被烤熟了。
思路:
首先去想这个最小时间是 然后设置每个锅的可使用时间是mintime,然后将汉堡肉按烤熟时间从大到小放进锅里面(其实可以按任意顺序),当某一口锅的时间被用满就换下一口,可以证明每份汉堡肉至多在两口锅中。然后输出答案即可。
证明:
假设红色是最大时间,紫色是第二大时间,整个矩形为可使用时间,由于每一口锅的可用时间都大于等于最大时间,所以有下图,说明同一份汉堡肉至多在两口锅且不会出现同一时间在两口锅的情况。由于是最大的两个都不会同一时间在两口锅,那么任意顺序进入锅中也是正确的了。
//author: TTDragon #include<bits/stdc++.h> typedef long long ll; const ll maxn=1e5+7; using namespace std; int _,n,m; struct node{ int num; ll val; int pan1,pan2; //时间记得开ll ,防止最小时间是sum/m的情况 ll l1,l2; ll r1,r2; bool operator < (node o) const { return val>o.val; } }a[maxn]; bool cmp(node a,node b) { return a.num<b.num; } ll sum,mx; ll sur[maxn];//每个锅的剩余可使用时间 int main() { cin.tie(nullptr)->sync_with_stdio(false); //freopen("in.in","r",stdin); //freopen("mine.out","w",stdout); cin>>n>>m; for(int i=1;i<=n;i++) { cin>>a[i].val; a[i].num=i; sum+=a[i].val; mx=max(mx,a[i].val); } //确定最大时间,剩下就是乱搞 if(sum%m==0) mx=max(mx,sum/m); else mx=max(mx,sum/m+1); for(int i=1;i<=n;i++) { sur[i]=mx; } //这里我们按耗时大到小排序,排不排无所谓 sort(a+1,a+n+1); int pannum=1; for(int i=1;i<=n;i++) { if(sur[pannum]>=a[i].val)//只用一个锅 { a[i].pan1=pannum; a[i].l1=mx-sur[pannum]; sur[pannum]-=a[i].val; a[i].r1=mx-sur[pannum]; a[i].pan2=-1; } else { a[i].pan1=pannum; a[i].l1=mx-sur[pannum]; a[i].val-=sur[pannum]; sur[pannum]=0; a[i].r1=mx; pannum++; //如果要用2口锅,2号锅一定要在1号锅前输出 a[i].pan2=pannum; a[i].l2=mx-sur[pannum]; sur[pannum]-=a[i].val; a[i].r2=mx-sur[pannum]; } //结束的时候判一下,我感觉有点多余 if(sur[pannum]==0) { pannum++; } } //编号乱了,调整回来 sort(a+1,a+n+1,cmp); for(int i=1;i<=n;i++) { if(a[i].pan2==-1) { cout<<1<<" "<<a[i].pan1<<" "<<a[i].l1<<" "<<a[i].r1<<endl; } else { cout<<2<<" "<<a[i].pan2<<" "<<a[i].l2<<" "<<a[i].r2<<" "<<a[i].pan1<<" "<<a[i].l1<<" "<<a[i].r1<<endl; } } return 0; }