Official
C - 特売セールの選択 / Bargain Sale Selection Editorial by admin
Gemini 3.0 Flash概要
\(N\) 個の商品を「通常価格」か「セール価格」のどちらかで購入します。セール価格で購入できるのは最大 \(K\) 個までという制限がある中で、合計金額を最小化する問題です。
考察
この問題のポイントは、「クーポンを使うことで、どれだけ安くなるか」という割引額に着目することです。
- 割引額の計算: 各商品 \(i\) について、通常価格 \(A_i\) とセール価格 \(B_i\) の差を \(D_i = A_i - B_i\) とします。この \(D_i\) は「商品 \(i\) にクーポンを使ったときに得をする金額」を表します。制約より \(A_i \geq B_i\) なので、この値は必ず \(0\) 以上になります。
- 言い換え: 「合計金額を最小化する」という目的は、「全ての商品を通常価格で購入すると仮定し、そこからクーポンを使って割引額の合計を最大化する」と言い換えることができます。
- 貪欲法(Greedy)の適用: 割引額 \(D_i\) が大きい商品から順にクーポンを適用していくのが最も効率的です。クーポンは最大 \(K\) 個まで使えるため、割引額が大きい上位 \(K\) 個の商品を選べば、全体の購入金額を最小に抑えることができます。
アルゴリズム
以下の手順で解を求めます。
- 全ての商品を通常価格で購入したときの合計金額
total_a(\(\sum A_i\))を計算します。 - 各商品の割引額 \(D_i = A_i - B_i\) を計算し、リストに格納します。
- 割引額のリストを降順(大きい順)にソートします。
- ソートしたリストの先頭から最大 \(K\) 個までの要素の和
max_savingsを求めます。 total_a - max_savingsが求める最小の合計金額となります。
計算量
- 時間計算量: \(O(N \log N)\)
- 割引額の計算に \(O(N)\)、ソートに \(O(N \log N)\)、上位 \(K\) 個の和の計算に \(O(K)\) かかります。全体ではソートが支配的になります。
- 空間計算量: \(O(N)\)
- 割引額を保存するためのリストに \(O(N)\) のメモリを使用します。
実装のポイント
高速な入出力: Pythonで \(N=2 \times 10^5\) 程度の入力を処理する場合、
input()を繰り返すよりもsys.stdin.read().split()などで一括で読み込む方が高速です。ソートの順序:
sort(reverse=True)を使って降順にするか、昇順にソートした後に後ろから \(K\) 個取ることで、割引額の大きいものを選べます。スライスの活用: Pythonでは
diffs[:k]のようにスライスを使うことで、簡単に上位 \(K\) 個を取り出すことができます。もし \(K > N\) であってもエラーにならず、リストの全要素が対象となるため安全です(本問題の制約では \(K \leq N\) ですが、汎用的な書き方です)。ソースコード
import sys
def solve():
# 標準入力から全てのデータを読み込み、スペースや改行で分割してリストにします
# 競技プログラミングにおいて、大量の入力を高速に処理する一般的な手法です
input_data = sys.stdin.read().split()
if not input_data:
return
# イテレータを使用してデータを1つずつ取り出します
it = iter(input_data)
# N: 商品の個数, K: クーポンを使用できる最大個数
n = int(next(it))
k = int(next(it))
total_a = 0
diffs = [0] * n
for i in range(n):
a = int(next(it))
b = int(next(it))
# 全ての商品を通常価格で購入した場合の合計金額を計算
total_a += a
# 通常価格とセール価格の差(クーポンによる割引額)を計算
# 制約より B_i <= A_i なので、この値は必ず0以上になります
diffs[i] = a - b
# 割引額が大きい順にソートします
diffs.sort(reverse=True)
# 最大でK個の商品にクーポンを適用できるため、
# 割引額が大きい方から最大K個を選んで合計金額から差し引きます
# スライス diffs[:k] は、kがリストの長さを超えても適切に処理されます
max_savings = sum(diffs[:k])
# 購入金額の合計の最小値を出力
print(total_a - max_savings)
if __name__ == '__main__':
solve()
この解説は gemini-3-flash-preview によって生成されました。
posted:
last update: