题目大意:
给定 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+m−1),然后直接构造即可,少了不够移往下一个锅,然后直接构造即可
#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
*/