頭がこんがらがる...
考え方
2次元座標で考えるのが大事.チョコと箱を(縦, 横)でソートしておく.チョコの大きい順に見ていき,なるべくギリギリ入る箱を削除して(使って)いけば良い(使った箱しか候補から削除できない.「勘違いしたこと」を参照.).
チョコはソート順に見ていくので配列でよいが,箱は
- ソート順を保ったままの配列で,
- 横の長さに対する二分探索を行い,
- 途中で要素の追加 / 削除を行う
原理的には,昇順で見ていくこともできそうだが,チョコを降順で見ていく場合は使える箱の「縦」の情報を捨てて良いのに対し,昇順で見ると「縦」の情報を捨てられない(降順で見る場合は,今見ているより「縦」が大きなチョコはないから,「縦」がチョコ以上の未使用の箱の中から「横」がギリギリのものを選べば良い.昇順で見る場合は,今見ているチョコより「縦」が大きな物があるから,「縦」も「横」もギリギリの箱を選ばなければならない).
よって,チョコを降順に見ていく.
- 縦が一番大きいチョコを選ぶ.
- 今見ているチョコ以上の「縦の長さ」をもつ箱の「横の長さ」を
multiset
にinsert
する(※これ以降見るチョコの「縦」はmultiset
に入っている「縦」以下なので,不要な情報.逆にあるとlower_bound
が上手くいかなくなる.). - 「チョコの横」以上の横を持つ箱のなかで,最小のものを
erase
する.これは,lower_bound
で求められる.マッチング数をカウントするカウンタを+1する. - 上記を全てのチョコに対して実行する.
- カウンタ=NならYes, そうでないならNoを出力する.
回答例
イテレータについて:AI - 4.04.イテレータ#include <bits/stdc++.h> using namespace std; int main() { int N, M; cin >> N >> M; vector<pair<int, int>> cho(N), box(M); for (int i = 0; i < N; i++) { cin >> cho.at(i).first; } for (int i = 0; i < N; i++) { cin >> cho.at(i).second; } for (int i = 0; i < M; i++) { cin >> box.at(i).first; } for (int i = 0; i < M; i++) { cin >> box.at(i).second; } sort(cho.rbegin(), cho.rend()); sort(box.rbegin(), box.rend()); multiset<int> s; auto it_box = box.begin(); for (int i = 0; i < N; i++) { while (it_box < box.end() && (*it_box).first >= cho.at(i).first) { s.insert((*it_box).second); it_box++; } auto it_s = s.lower_bound(cho.at(i).second); if (it_s == s.end()) { cout << "No" << endl; return 0; } s.erase(it_s); } cout << "Yes" << endl; return 0; }
【参考】AtCoder Beginner Contest 245 - YouTube (Submission #30488624 - AtCoder Beginner Contest 245)
勘違いしたこと
はじめ,チョコレートと箱をそれぞれソート((縦, 横)でソート)しておけば,「$i$番目のチョコが$j$番目の箱に入らなければ,$i^{\prime} (> i)$番目のチョコは$j^{\prime} (\geq j)$番目の箱には入らない」と考えた.もし,これが成り立つなら,以下のようにチョコと箱を小さい順に見て,入らない箱は捨てていけばよい.しかし,実際は上は成り立たず,チョコの順序と箱への入りやすさが逆転する例がある.例えば,
- チョコ:
[(1, 3), (2, 1)]
- 箱:
[(2, 2), (2, 3)]
よって,チョコが入らないからと言って,箱を捨てることはできない.
【誤答】
N, M = map(int, input().split()) A = list(map(int, input().split())) B = list(map(int, input().split())) C = list(map(int, input().split())) D = list(map(int, input().split())) cho = [(a, b) for a, b in zip(A, B)] box = [(c, d) for c, d in zip(C, D)] cho.sort(reverse = True) box.sort(reverse = True) cnt = 0 while (cho and box): a, b = cho.pop() while box: c, d = box.pop() if a <= c and b <= d: cnt += 1 break print('Yes' if cnt == N else 'No')