T1P11289 【MX-S6-T1】「KDOI-11」打印
这道题是贪心+单调队列,主要就是考单调队列的。
来看看暴力45分做法。
使用一个优先队列存储每个节点信息,然后每次取队顶,对于每一次时间增加我们重新更新队列。
由于优先队列不支持直接修改,也没有迭代器,因此我们只能一个一个更新出队再进队,所以非常费时。
#include <bits/stdc++.h>
using namespace std;
#define maxn int(2e5)
#define _for(a,b,c) for(int i = a;i <= b;i+=c)
struct p{
int nxt,id;
bool operator < (const struct p &a) const{
return nxt == a.nxt ? id > a.id : nxt > a.nxt;
}
};
priority_queue<p> q;
struct wj{
int s,t,id;
} w[maxn];
bool cmp(wj A,wj B){
return A.t < B.t;}
int read(){
int X=0,w=0; char c=0;
while(c<'0'||c>'9') {
w|=c=='-';c=getchar();}
while(c>='0'&& c<='9') X=(X<<3)+(X<<1)+(c^48),c=getchar();
return w? -X : X;
}
vector<int> ans[maxn+10];
int c1[maxn+10],c2[maxn+10];
signed main(){
int n = read(),m = read();
_for(1,n,1) w[i].s = read(),w[i].t = read(),w[i].id = i;
sort(w+1,w+1+n,cmp);
_for(1,m,1) q.push(p{
0,i});
_for(1,n,1){
int tot = 0;
while(!q.empty()){
int tmp1 = q.top().nxt;
tmp1 -= (w[i].t - w[i-1].t);
if(tmp1 < 0) tmp1 = 0;
int tmp2 = q.top().id;
q.pop();
c1[++tot] = tmp1,c2[tot] = tmp2;
}
for(int j = 1;j <= tot;j++){
q.push((p){
c1[j],c2[j]});
}
//printf("%d %d\n",q.top().nxt,q.top().id);
ans[q.top().id].push_back(w[i].id);
int tmp = q.top().nxt + w[i].s;
int tmp2 = q.top().id;
q.pop();
q.push((p){
tmp,tmp2});
}
_for(1,m,1){
printf("%d ",ans[i].size());
sort(ans[i].begin(),ans[i].end());
for(int j = 0;j < ans[i].size();j++) printf("%d ",ans[i][j]);
printf("\n");
}
return 0;
}
接下来想想正解:
首先按照下发命令的 t t t给它排序,接下来考虑一个一个的分配给打印机。
由于每次会选择等待时间最短的打印机,所以可以用两个优先队列来维护,一个优先队列 q q q用来维护当前需要等待的打印机要等多久以及其编号,另一个 n u m num num用来维护不用等待的打印机的编号。
每一次先把已经打印完的打印机出队,并让这些打印机的编号插入 n u m num num,接下来开始判断当前这个文件该用哪个打印机来打印,有以下两种情况:
- n u m num n