Official
E - 本棚への配架 / Shelving Books on a Bookshelf Editorial
by
E - 本棚への配架 / Shelving Books on a Bookshelf Editorial
by
kyopro_friends
問題文に記載の通りの操作を実際に行おうとすると、次のようなケースで 本 1 冊あたり \(\Omega(M)\) 時間、全体で \(\Omega(NM)\) 時間かかり、実行時間制限に間に合わせることは困難です。
200000 200000 200000 199999 199998 ... 3 2 1 1 2 3 ... 199998 199999 200000
本を挿入する箇所を二分探索できないか考えます。
「スペース \(x\) までにこの本を入れることができる箇所はあるか?」を判定するためには、「スペース \(1,2,\dots, x\) のうちまだ本が置かれていないものの耐荷重の最大値」がわかれば十分です。また既に本が置かれたスペースは耐荷重を \(0\) に置き換えることで無視することができます。
よって、区間最大値取得と 1 点更新を高速に行えるデータ構造があればよいことがわかりました。これはセグメントツリーにより実現できます。
ACL のセグメントツリーには二分探索のための機能が存在するため、これを適切に利用することでこの問題を \(O((N+M)\log N)\) で解くことができます。
実装例 (C++)
#include<bits/stdc++.h>
#include<atcoder/segtree>
using namespace std;
int main(){
int n, m;
cin >> n >> m;
vector<int> w(n);
for(int i=0; i<n; i++) cin >> w[i];
vector<int> c(m);
for(int i=0; i<m; i++) cin >> c[i];
auto e = [](){return 0;};
auto op = [](int x, int y){return max(x, y);};
atcoder::segtree<int, op, e> seg(c);
int ans = 0;
for(int i=0; i<n; i++){
auto f = [&](int x){return x < w[i];};
int r = seg.max_right(0, f);
if(r != m){
ans++;
seg.set(r, 0);
}
}
cout << ans << endl;
}
実装例 (Python)
from atcoder.segtree import SegTree
N, M = map(int,input().split())
W = list(map(int,input().split()))
C = list(map(int,input().split()))
seg = SegTree(max, 0, C)
ans = 0
for w in W:
f = lambda x: x < w
r = seg.max_right(0, f)
if r != M:
ans += 1
seg.set(r, 0)
print(ans)
posted:
last update:
