2021牛客暑期多校训练营6 F Hamburger Steak

F Hamburger Steak

题目大意:

给定 n n n个牛排, m m m个锅,每个牛排需要煎 a i a_i ai分钟,一个牛排可以一次煎,也可以分成两次煎,要求煎的总时间最小

构造一组方案,需要输出每个牛排,在几个锅(最多两个)里煎,要输出,在哪个锅煎,煎的开始时间,结束时间,同时满足时间总和最小

比赛时的错误想法大赏:

想法一:维护一个优先队列,从小到大放入牛排,满足优先队列大小为m,想将最大的m个按顺序装入,把优先队列装满后,在将剩余的牛排往优先队列中最小的加(动态)

然后是调整:

将所有的锅中的内容出队(从小到大),每次将当前最大的与最小的差,将差除以 2 2 2,然后放在,最少的最下面,每次动态调整数组即可

如下图

在这里插入图片描述

手动模拟数组,输出即可

错误代码演示:

#include <bits/stdc++.h>
#define inf 0x7fffffff
//#define ll long long
#define int long long
//#define double long double
//#define double long long
#define re int
//#define void inline void
#define eps 1e-8
//#define mod 1e9+7
#define ls(p) p<<1
#define rs(p) p<<1|1
#define pi acos(-1.0)
#define pb push_back
#define mk make_pair
#define P pair < int , int >
using namespace std;
const int mod=1e9+7;
//const int inf=1e18;
const int M=1e8;
const int N=1e5+5;//??????.???? 4e8
struct node
{
	stack < int > qwq,st;
	int val;
	int id;
}a[N];
bool operator < (const node & a ,const node &b)
{
	return a.val>b.val;
}
struct nc
{
	int val,id;
}b[N];
priority_queue < node > q;
struct qeju
{
	int l[3],r[3],t;
	int id[3];
}e[N];
int n,m; 
bool cmp(nc i,nc j)
{
	return i.val>j.val;
}
void solve()
{
	cin>>n>>m;
	for(re i=1;i<=n;i++)  scanf("%lld",&b[i].val),b[i].id=i;
	if(n<=m)
	{
		for(re i=1;i<=n;i++)
		{
			printf("1 %lld 0 %lld\n",i,b[i].val);
		}
		return;
	} 
	sort(b+1,b+n+1,cmp);
	for(re i=1;i<=m;i++)
	{
		a[i].qwq.push(b[i].id);
		a[i].val+=b[i].val;
		a[i].id=i;
		a[i].st.push(b[i].val);
		q.push(a[i]);
	}
//	cout<<m<<endl;
	for(re i=m+1;i<=n;i++)
	{
		node t=q.top();
		q.pop();
		t.qwq.push(b[i].id);
		t.val+=b[i].val;
		t.st.push(b[i].val);
		q.push(t);
	}
//	cout<<q.size()<<endl;
	for(re i=m;i>=1;i--)  
	{
		a[i]=q.top();
		q.pop();
	}
//	for(re i=1;i<=m;i++)  printf("%lld ",a[i].val);puts("");
	int l=1,r=m;
	while(l<r)
	{
		
		int x=a[r].val-a[l].val;
		int id=a[r].qwq.top();
		x/=2;
		if(x==0)
		{
			l++,r--;
			continue;
		}
		a[r].val-=x;
		a[l].val+=x;
		a[l].qwq.push(id);
		a[l].st.push(x);
		int y=a[r].st.top();
//		a[r].st.pop();
		y-=x;
		a[r].st.push(y);
		r--;
		if(a[l].val>=a[l+1].val)  l++;
//		cout<<a[r].qwq.size()<<" "<<a[r].st.size()<<endl;
	}
	for(re i=1;i<=m;i++)
	{
		int x=0;
		while(!a[i].qwq.empty())
		{
			int id=a[i].qwq.top();
			a[i].qwq.pop();
			int len=a[i].st.top();
			a[i].st.pop();
			int idg=a[i].id;
			e[id].t++;
			int t=e[id].t;
			e[id].id[t]=idg;
			e[id].l[t]=x;
			x+=len;
			e[id].r[t]=x;
//			cout<<len<<" "<<x<<" "<<idg<<" "<<id<<endl;
		}
	}
//	cout<<e[1].l<<endl;
	for(re i=1;i<=n;i++)
	{
		printf("%lld ",e[i].t);
		for(re j=1;j<=e[i].t;j++)   printf("%lld %lld %lld ",e[i].id[j],e[i].l[j],e[i].r[j]);
		puts("");
	}
}
signed main()
{
    int T=1;       
//    cin>>T;
    for(int index=1;index<=T;index++)
    {
        solve();
//        puts("");
    }
    return 0;
}
/*

4
4 2
2 2
4 4




5
3 2
2 2
3 1 

5 1
4 1

5 2
5 1
3 3 

5 1
5 4


6 3
5 1
2 2
3 3




*/

错误做法2:

x 2 \frac{x}{2} 2x用一个队列维护,想将队列输完,在输出数组中的

错误做法3:

用平衡树动态维护,但是觉得过的人太多就pass了

正解:

考虑需要的最少时间,应当是 m a x ( m a x a i , s u m + m − 1 m ) max(max a_i,\frac{sum+m-1}{m}) max(maxai,msum+m1),然后直接构造即可,少了不够移往下一个锅,然后直接构造即可

#include <bits/stdc++.h>
#define inf 0x7fffffff
//#define ll long long
#define int long long
//#define double long double
//#define double long long
#define re int
//#define void inline void
#define eps 1e-8
//#define mod 1e9+7
#define ls(p) p<<1
#define rs(p) p<<1|1
#define pi acos(-1.0)
#define pb push_back
#define mk make_pair
#define P pair < int , int >
using namespace std;
const int mod=1e9+7;
//const int inf=1e18;
const int M=1e8;
const int N=4e5+5;//??????.???? 4e8
int n,m;
int a[N];
int tim,pos,ans,sum;
void solve()
{
	cin>>n>>m;
	for(re i=1;i<=n;i++)  scanf("%lld",&a[i]),ans+=a[i],sum=max(a[i],sum);
	ans=max((ans+m-1)/m,sum);
	pos=1;
	for(re i=1;i<=n;i++)
	{
		if(a[i]+tim<=ans)
		{
			printf("1 %lld %lld %lld\n",pos,tim,tim+a[i]);
			tim+=a[i];
			if(tim==ans)  tim=0,pos++;
		}
		else 
		{
			printf("2 %lld 0 %lld %lld %lld %lld\n",pos+1,a[i]-(ans-tim),pos,tim,ans);
			tim=a[i]-(ans-tim);
			pos++;
		}
	}
}
signed main()
{
    int T=1;       
//    cin>>T;
    for(int index=1;index<=T;index++)
    {
        solve();
//        puts("");
    }
    return 0;
}
/*

4
4 2
2 2
4 4




5
3 2
2 2
3 1 

5 1
4 1

5 2
5 1
3 3 

5 1
5 4


6 3
5 1
2 2
3 3




*/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值