公式
E - 印刷工場のスケジュール / Print Factory Schedule 解説
by
ポスターの印刷機への割り当てを任意に1つ取り☆とする。☆と★で印刷機への割り当て方が異なるポスターがあれば、そのうち $W$ が最小のポスターを $i$ であるとする。★でポスター $i$ が割り当てられている印刷機を $j$ とする。このとき、☆に対して適当な操作をすることで、幅が $W$ より小さいポスターの割り当てを変更することなく、ポスター $i$ の割り当てを印刷機 $j$ に変更できることを示す。
①☆で印刷機 $j$ にまだ空きがあれば、ポスター $i$ の割り当てを印刷機 $j$ に変更することができる。
②☆で印刷機 $j$ に空きがないとき、☆でポスター $i$ が割り当てられている印刷機を $j'$ とする。$W$ の最小性の仮定から、印刷機 $j$ に割り当てられているポスター $i'$ であって、$W_i \leq W_{i'}$ であるものが存在する。このとき、★の割り当て方から $R_j \leq R_{j'}$、☆の割り当てから $L_{j'} \leq W_i \leq R_{j'}$ 及び $L_j \leq W_{i'} \leq R_j$ が成り立つので $L_{j'} \leq W_i \leq W_{i'} \leq R_j \leq R_{j'}$ であり、ポスター $i'$ は印刷機 $j'$ に割り当てることができる。よってポスター $i$ とポスタ $i'$ の割り当てを入れ替えることで、ポスター $i$ の割り当てを印刷機 $j$ に変更することができる。
以上の操作を繰り返すことで、☆を★に一致させることができる。
E - 印刷工場のスケジュール / Print Factory Schedule 解説
by
kyopro_friends
この問題は答えを二分探索することで解くことができます。
「 \(D\) 日以内に完了できるか?」という判定問題を考えます。
ポスターの印刷機への割り当てを \(W\) の昇順に「そのポスター を割り当てることが可能な印刷機のうち、 \(R\) が最小のものから貪欲に割り当てる」(★)として決めます。\(D\) 日以内に完了できるなら、この方法により必ず割り当てを求めることができます。
証明
全ての $i$ について、$C_i$ 枚のポスターを全て相異なるものとみなし、$\sum C_i$ 種類のポスターそれぞれについて、印刷機への割り当てを考える。また、$W$ や $R$ などでの比較は適当なタイブレークにより順序が一意に定まるものとする。ポスターの印刷機への割り当てを任意に1つ取り☆とする。☆と★で印刷機への割り当て方が異なるポスターがあれば、そのうち $W$ が最小のポスターを $i$ であるとする。★でポスター $i$ が割り当てられている印刷機を $j$ とする。このとき、☆に対して適当な操作をすることで、幅が $W$ より小さいポスターの割り当てを変更することなく、ポスター $i$ の割り当てを印刷機 $j$ に変更できることを示す。
①☆で印刷機 $j$ にまだ空きがあれば、ポスター $i$ の割り当てを印刷機 $j$ に変更することができる。
②☆で印刷機 $j$ に空きがないとき、☆でポスター $i$ が割り当てられている印刷機を $j'$ とする。$W$ の最小性の仮定から、印刷機 $j$ に割り当てられているポスター $i'$ であって、$W_i \leq W_{i'}$ であるものが存在する。このとき、★の割り当て方から $R_j \leq R_{j'}$、☆の割り当てから $L_{j'} \leq W_i \leq R_{j'}$ 及び $L_j \leq W_{i'} \leq R_j$ が成り立つので $L_{j'} \leq W_i \leq W_{i'} \leq R_j \leq R_{j'}$ であり、ポスター $i'$ は印刷機 $j'$ に割り当てることができる。よってポスター $i$ とポスタ $i'$ の割り当てを入れ替えることで、ポスター $i$ の割り当てを印刷機 $j$ に変更することができる。
以上の操作を繰り返すことで、☆を★に一致させることができる。
この割り当て方は高速にシミュレーションすることができます。具体的には、印刷機を \(L\) の昇順にソートし、ポスターを \(W\) の昇順に見ながら、各印刷機の残りの容量と「いま見ているポスターを処理することができる印刷機を \(R\) の昇順に取り出せる優先度付きキュー」を更新すればよいです。
以上により、 \(O((N+M)\log M\log \sum C_i+N\log N)\) 時間でこの問題を解くことができます。
実装例 (C++)
#include<bits/stdc++.h>
using namespace std;
int main(){
int n, m;
cin >> n >> m;
vector<array<int, 2>> wc(n);
for(int i=0; i<n; i++) cin >> wc[i][0] >> wc[i][1] >> wc[i][1];
sort(wc.begin(), wc.end());
vector<array<int, 2>> lr(m);
for(int i=0; i<m; i++) cin >> lr[i][0] >> lr[i][1];
sort(lr.begin(), lr.end());
auto solve=[&](int mid){
priority_queue<array<int,2>>q;
int pos=0;
for(int i=0; i<n; i++){
auto [w, c] = wc[i];
while(pos < m && lr[pos][0] <= w){
q.push({-lr[pos][1], mid});
pos++;
}
while(c){
if(q.empty()){
return false;
}
auto[r, cnt]=q.top(); q.pop();
r = -r;
if(w <= r){
int x = min(c, cnt);
c -= x;
cnt -= x;
if(cnt > 0){
q.push({-r, cnt});
}
}
}
}
return true;
};
const int INF = 1e9 + 1;
int ok = INF, ng = 0;
while(ok - ng > 1){
int mid = (ok + ng) / 2;
if(solve(mid)){
ok = mid;
}else{
ng = mid;
}
}
if(ok == INF){
cout << -1 << endl;
}else{
cout << ok << endl;
}
}
Python の場合、実装時間制限がきついため、例えば input ではなく stdin.readline を使うなどの工夫が必要であることに注意してください。
実装例 (Python)
import heapq
from sys import stdin
input = stdin.readline
N, M = map(int, input().split())
WC = []
for _ in range(N):
W, _, C = map(int, input().split())
WC.append((W, C))
WC.sort()
LR = [tuple(map(int,input().split())) for _ in range(M)]
LR.sort()
def solve(mid):
q = []
pos = 0
for w, c in WC:
while pos < M and LR[pos][0] <= w:
heapq.heappush(q, (LR[pos][1], mid))
pos += 1
while c:
if len(q) == 0:
return False
R, cnt = heapq.heappop(q)
if w <= R:
x = min(c, cnt)
c -= x
cnt -= x
if cnt > 0:
heapq.heappush(q, (R, cnt))
return True
INF = 10**9 + 1
ok = INF
ng = 0
while ok - ng > 1:
mid = (ok + ng) // 2
if solve(mid):
ok = mid
else:
ng = mid
if ok == INF:
print(-1)
else:
print(ok)
投稿日時:
最終更新:
