AtCoder Beginner Contest 141 D - 今日から始める競プロ日記
はじめに
AtCoder Beginner Contest 141 ( ABC 141 ) に参加。
D問題でだいぶ躓いてしまったので、 解いた方針をまとめておく。
ちなみに、priority_queue の存在を忘れていて、 結局 multiset を使って解いた。
この記事では priority_queue を使ったほうでまとめる。
D - Powerful Discount Tickets
- N個の品物を買う。
- i番目の品物の値段はAi
- 割引券をM枚持っている
- 任意の品物に対して任意の枚数の割引券を使うことができる
- 割引券一枚で半額(小数点以下切り捨て)
- 最小いくらで買い物ができるか求めよ
解いた方針
方針はすぐに立った。
一番値段が高い品物から順々に割引券を使っていけば良い。
問題は実装方法。
一番大きい値段を知るために、
常に配列をソートした状態にしたいが、
愚直にやるとO(NM)
になるはずだからダメ。
だからデータをどの型で扱うかを考える必要がある。
私はmultiset
を使って解いたけど、
解説を読んだらpriority_queue
を使うといいよって書いてあって、
「聞いたことある~」とちょっと悲しくなった。
コンテスト中にもっと早く気づきたかった。
コード
#include <bits/stdc++.h> using namespace std; typedef long long ll; int main() { // 入力 ll N, M; cin >> N >> M; priority_queue<ll> pq; // ソートの状態でデータを保持 for(int i = 0; i < N; i++) { ll a; cin >> a; pq.push(a); } // M回分、最大値を半分に for(int i = 0; i < M; i++) { ll maxv = pq.top() / 2LL; pq.pop(); pq.push(maxv); } // 合計値を計算 ll sum = 0; for(int i = 0; i < N; i++) { sum += pq.top(); pq.pop(); } // 解を出力 cout << sum << endl; return 0; }
おわりに
D問題までを早解きできるようになりたい(目標は三十分)。