besthacker2的第二题,模拟了22遍才模拟对,详细看代码吧,所有细节都已标出。
附代码:
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
int n,t,k,m;
struct node
{
int st,et,p,v,mb;
} cc[1001];
int main()
{
int T;
cin>>T;
while (T--)
{
scanf("%d%d%d%d",&n,&t,&k,&m);
for (int i=1;i<=m;i++)
{
int a,b;
int p,v;
scanf("%d:%d%d%d",&a,&b,&p,&v);
cc[i].st=a*60+b;
cc[i].p=p;
cc[i].v=v;
cc[i].mb=0;
}
int cur=1;
for (int i=cc[1].st;;i+=t) //i代表当前这次炒饭的起始时间
{
int p=cc[cur].p;
int v=k; //当前这次炒饭最多炒这么多
if (v<cc[cur].v)
{
int d=(cc[cur].v-v)/k; //如果当前这次炒最多也不够当前人的量,当前继续炒同一种,直至超过当前人的需要
if ((cc[cur].v-v)%k!=0)
d++;
v=v+(d)*k;
i=i+(d)*t;
}
int j;
int pp=0;
for (j=cur;j<=m&&cc[j].st<=i;j++) //从当前人开始向后查在开始炒之前所有需要这种炒饭的总份数,如果能满足则直接满足
{
if (cc[j].mb==1) //如果已经满足过,直接跳过
continue ;
if (cc[j].p==p&&cc[j].v<=v) //当前的炒饭种类和分数满足当前这个人的需要
{
v-=cc[j].v; //满足他,然后看剩余部分是否够下个人的
cc[j].et=i+t; //此人走的时间为当前这份炒饭炒完的时间
cc[j].mb=1; //标记为已经满足
continue ;
}
if (pp==0) //如果当前的分数或者种类不满足,则下一个需要满足的人肯定是他(队首位置)
{
cur=j;
pp=1;
}
if (cc[j].p==p) //如果当前没有到末尾且炒饭种类一样,但是不能满足需求,那么肯定是份数不够,先满足部分
break;
}
if (j<=m&&cc[j].st<=i) //先满足此人部分的情况
cc[j].v-=v;
if (pp==0) //如果在开始这次炒饭时间之前的人的需求都满足了,则直接把下一个时刻来的人设为要满足的人
{
cur=j;
if (cur>m) //如果当前需要满足的人已经超过队列长度,则处理完毕
break;
i=cc[cur].st-t>i?cc[cur].st-t:i; //下一个开始炒饭时间为下一个人来的时间和这次炒饭完成时间的较大者,循环中+t
}
}
for (int i=1;i<=m;i++)
{
int a=cc[i].et/60;
a%=24;
int b=(cc[i].et)%60;
printf("%02d:%02d\n",a,b);
}
if (T)
printf("\n");
}
}