显示代码纯文本
/*
使用优先队列来模拟这个过程。
我们把多个农民同时完成的情况称为一个事件。
对于每个事件,存储完成的农民集合。
暂时以任意顺序将接下来的几头牛分配给这些农民。
由此,我们可以确定贝西(Bessie)面试的时间。
考虑如果我们按时间逆序遍历这些事件会发生什么。
如果农民 x 在某事件里,那么任何与他同时完成的农民都可能是贝西的面试官。
实际上,当我们逆着时间回溯时,每当贝西可能的面试官集合与一个事件中的农民集合相交时,
该事件中的任何农民都可能最终成为贝西的面试官。
*/
#include <bits/stdc++.h>
using namespace std;
using LL = long long;
using pli = pair<LL, int>;
#define cost first
#define id second
int main() {
freopen("interview.in","r",stdin);
freopen("interview.out","w",stdout);
int n, k;
cin >> n >> k;
vector<LL> t(n);
for (int i = 0; i < n; i++) cin >> t[i];
//小顶堆,先按first升序,first相等,按second升序
priority_queue<pli, vector<pli>, greater<pli> > q;
for (int i = 0; i < k; i++) q.push({t[i], i});
//先入队k头牛让k名农夫面试
int cur_cow = k;//当前待面试的奶牛编号
pli last;
vector<vector<int>> events;
while (true) {
vector<pli> ev;
do {//将和队头农民一起结束当前面试的农民存入 ev
ev.push_back(q.top());//
q.pop();
} while (!q.empty() && q.top().cost == ev[0].cost);
if (ev.size() > 1) {//将同一事件的农民存入events
vector<int> farmers;
for (pli e : ev) farmers.push_back(e.id);
events.push_back(farmers);//
}
if (cur_cow + ev.size() > n) {
last = ev[0];//除贝西外最后一头面试的牛
break;
}
for (pli e : ev) {//将后续待面试的牛逐个分给本批次农民
q.push({e.cost + t[cur_cow], e.id});//当前面试花费的时间+待面试牛的花费时间
cur_cow++;
}
}//end while
cout << last.cost << "\n";
vector<bool> can_interview(k, false);
can_interview[last.id] = true;//上面求出的面试贝西的农民
//按时间逆序遍历每个事件农民集合
for (int i = (int)events.size() - 1; i >= 0; i--) {
bool intersect = false;
for (int j : events[i]) {
if (can_interview[j]) {//本批有可能面试贝西的农民
intersect = true;
break;
}
}
if (intersect) {//如果本批有可能面试贝西的农民,则本批均可能面试贝西
for (int j : events[i]) {
can_interview[j] = true;
}
}
}
vector<int> ans;
for (int i = 0; i < k; i++) {
cout << can_interview[i]<<(i==k-1?"\n":"");
}
return 0;
}