模拟题。感觉跟某次 CSP 的第四题有点像,是它的简化版。
维护 n 个队列,长度均 <= m,每个队列记录其下一个客户可以开始的时间(或者称为当前正在处理的客户的完成时间)。每次遍历所有队列,找出完成时间最早的那个,更新相应的客户的完成时间,并将其移除出该队列。同时,若还有客户在黄线以外,则将其加入该队列(这样就能保证 <= m 了)。反复执行,直到遍历所有队列后发现,所有队列的最早完成时间都在 17:00 之后了,这时,坑来了。即使银行 17:00 关门,但仍要等待 17:00 前就开始的客户的业务完成。所以,需要遍历一遍所有队列,将所有已经开始(意味着开始时间 <= 16:59)的客户的完成时间进行更新,然后退出循环。此时,17:00 (含)以后才能开始的客户都无法开始了(”Sorry“),而 17:00 以前开始的客户都有了结束的时间。
#include <bits/stdc++.h>
using namespace std;
const int maxn = 20+2;
const int maxk = 1e3+3;
const int maxt = 540;
struct Window {
int next; //下一个客户可以开始处理的时间
deque<int> line; //队列
void push_back(int x) {
line.push_back(x);
}
void pop_front() {
line.pop_front();
}
int front() {
return line.front();
}
int size() {
return line.size();
}
} w[maxn];
int n, m, k, q;
int t[maxk];
int ans[maxk];
void read() {
scanf("%d%d%d%d", &n, &m, &k, &q);
for (int i = 1; i <= k; ++i) {
scanf("%d", &t[i]);
if (i <= n*m) {
w[(i-1)%n].push_back(i);
}
}
}
void solve() {
int nextt, nextw;
int curk = min(n*m, k); //n*m可能大于k
while (true) {
nextt = maxt+1;
nextw = -1;
for (int i = 0; i < n; ++i) {
if (!w[i].size()) continue; //队列已经空了,不检查
int temp = w[i].next + t[w[i].front()]; //队首完成时间
if (nextt > temp) {
nextt = temp;
nextw = i;
}
}
if (nextt > maxt || nextw == -1) { //没有发现能在17:00前加入的
// 将在17:00加入的,并还没有完成的,计算完成时间
for (int i = 0; i < n; ++i) {
if (!w[i].size() || w[i].next >= maxt) continue;
int temp = w[i].next + t[w[i].front()];
ans[w[i].front()] = temp;
}
// 之后的都是在17:00后才能加入的了,银行已经关门,结束
break;
}
w[nextw].next = nextt;
ans[w[nextw].front()] = nextt;
w[nextw].pop_front();
if (++curk <= k) { //如果还有人没加入队列
w[nextw].push_back(curk);
}
}
}
void query() {
while (q--) {
int i;
scanf("%d", &i);
if (ans[i]) {
printf("%.02d:%.02d\n", ans[i]/60+8, ans[i]%60);
} else {
printf("Sorry\n");
}
}
}
int main() {
read();
solve();
query();
return 0;
}