【题解】
甲级凡是有问题,大多出在读题。
题意:有n个窗口,每个窗口黄线内可以排长度为m个人的队,总共有k个客户,每个客户有一个解决时间ti,q个询问,每次询问编号为x的客户在几点办完事情。
思路:我们看到,一天的工作时间是从8:00-17:00,共9个小时9*60=540分钟,数据比较小所以我们选择按时间枚举没有疑问。根据题目中的举例,我们可以看到,当黄线内没有满的时间,客户会优先选择队伍比较短窗口编号比较小的窗口进行排队,直到黄线内满员,然后再等待下一个或是几个办完事情的客户离开再进黄线排队。所以这里涉及到先进先出的问题,我选择了用队列维护,用数组加个标记指针也可以。
每次枚举时间,首先我们把要离开的客户送走,然后用剩下的客户去填满黄线内的位置。怎么判断客户要离开呢?这里我维护了一个每个窗口上一个走掉的客户的时间的数组sum[],每次只要判断基于上一个客户的时间加上这个客户所需要花费的时间是否等于当前的时间即可。需要注意的是,只要在17:00之前处理的客户(即使解决完时间超过17:00),都是输出对应时间。
【代码】
#include <bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
queue <int> q[25];
int sum[25]={0};
int a[1005],ans[1005];
int main()
{
int n,m,k,qq; scanf("%d%d%d%d",&n,&m,&k,&qq);
for(int i=1;i<=n;i++)
while(!q[i].empty()) q[i].pop();
for(int i=1;i<=k;i++) scanf("%d",&a[i]),ans[i]=-1;
int cnt=1;
for(int i=0;i<540;i++){ //枚举时间
for(int j=1;j<=n;j++){
if(!q[j].empty()){ //不为空,确认第一个是否可弹出
int num=q[j].front();
if(sum[j]+a[num]==i) ans[num]=sum[j]=i,q[j].pop();
}
}
while(cnt<=k){
int p=-1,mi=m;
for(int j=1;j<=n;j++){
int l=q[j].size();
if(l<mi){
mi=l;
p=j; //记录最短队伍
}
}
if(p==-1) break;
else q[p].push(cnt++);
}
}
for(int i=1;i<=n;i++)
if(!q[i].empty()) ans[q[i].front()]=sum[i]+a[q[i].front()];
while(qq--){
int x; scanf("%d",&x);
if(ans[x]==-1) printf("Sorry\n");
else printf("%02d:%02d\n",8+ans[x]/60,ans[x]%60);
}
return 0;
}