#include<iostream>
#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;
const int INF=1<<30,K=103;
struct node{
int come,cost,vip,serve,done;
node(int a,int b,int c,int d,bool e):come(a*3600+b*60+c),
cost(min(d*60,7200)),vip(e),done(false),serve(INF){}
};
typedef const node& cnr;
vector<node>man;
vector<int>fre;
int n,k,m,cnt[K],vip[K];
void prtime(int k){
printf("%02d:%02d:%02d ",k/3600,(k%3600)/60,k%3600%60);}
void play(node&he,int nth){
int began=max(he.come,fre[nth]);
he.done=true; ++cnt[nth]; he.serve=began;
fre[nth]=began+he.cost;
}
int main(){
scanf("%d",&n); man.reserve(10006);
for(int i=0,a,b,c,d,e;i<n;++i){
scanf("%d:%d:%d%d%d",&a,&b,&c,&d,&e);
man.emplace_back(a,b,c,d,e); }
sort(man.begin(),man.end(),[](cnr x,cnr y){return x.come<y.come;});
scanf("%d%d",&k,&m); fre.assign(k,8*3600);
for(int i=0,no;i<m;++i){ scanf("%d",&no); vip[no-1]=true; }
for(int cur=0;cur<man.size();++cur){
auto &he=man[cur]; if(he.done)continue;
int line=max(he.come,*min_element(fre.begin(),fre.end())); if(line>=21*3600)break;
int vipt=-1,vipu=-1,vopt=-1;
for(int i=0;i<k;++i) if(fre[i]<=line){
if(vopt==-1) vopt=i;
if(vip[i]&&vipt==-1)vipt=i;
}
for(int i=cur;i<n&&man[i].come<=line;++i)
if(man[i].vip&&vipu==-1&&!man[i].done) vipu=i;
if(vipu!=-1 &&vipt!=-1){ play(man[vipu],vipt);--cur; }
else play(he,vopt);
}//for(int cur...
sort(man.begin(),man.end(),[](cnr x,cnr y){return x.serve<y.serve;});
for(auto &x:man) if(x.serve!=INF){
prtime(x.come); prtime(x.serve); cout<<(x.serve-x.come+30)/60<<endl;}
for(int i=0;i<k;++i) cout<<(i?" ":"")<<cnt[i];
}
窗口排队的题首先都按用户到达时间排序,如果不插队的话,每个窗口记录自己的时间,只要不断用队头用户刷新窗口的记录时间即可。每次轮到队头用户时,可能有一些窗口空闲,可以选空闲窗口编号最小的,也可以选空闲窗口中释放时间最早的,都不影响结果;也可能没有窗口空闲,此时只能选释放时间最早的,因此一般题目不断用队头用户刷新释放时间最早的窗口的时间记录即可。例如advance level的1014 waiting in line 和1017 queueing at bank和数据结构题集里的8-05. 银行排队问题之“多队列多窗口”版 。
这个题如果分情况讨论的话很麻烦。分配一张桌子呢肯定是既有等待的用户又有空闲的桌子的时候,即max( 队头到达时间,min( 各窗口释放时间 ) ),以此时间为分界只有一种情况需要插队,即既有等待的vip用户又有空闲的vip桌子,让vip与vip先配对即可。否则让最先来的队头用户与最先释放的桌子配对即可。