D - お土産の配布 / Distribution of Souvenirs 解説 by admin
Qwen3-Coder-480B概要
\(N\) 人のメンバーに、\(M\) 種類のお菓子からそれぞれ最大1個ずつ選んで、1人あたりちょうど \(K\) 個を配ることが可能かを判定する問題。
考察
この問題では、各メンバーに \(K\) 個のお菓子を配る必要があります。ただし、同じ種類のお菓子を1人には最大1個しか渡せず、また各種類のお菓子には上限 \(C_i\) があります。
素朴な考え
例えば、メンバーごとに使えるお菓子の組み合わせを探索したり、フロー-basedなグラフアルゴリズムを適用することも考えられますが、制約が非常に大きい(\(N\) が最大 \(10^9\))ため、そういったアプローチでは時間内に解くことはできません。
鍵となる観察
重要なのは「お菓子の種類ごとに、最大何人に配れるか」を考えることです。
\(i\) 番目のお菓子は \(C_i\) 個あり、1人につき最大1個しか渡せないので、「最大 \(\min(C_i, N)\) 人に配れる」と考えられます。
これは、人数 \(N\) が少なければお菓子が余る可能性があり、逆にお菓子が少なければ人数分には配れない、という直感的な上限です。
さらに、全体で必要なのは \(N \times K\) 個のお菓子(1人 \(K\) 個 × \(N\) 人)です。
そのため、各お菓子の「配れる人数の上限」を足し合わせた値が、\(N \times K\) 以上になれば条件を満たせます。
解法の正当性
この貪欲なアプローチが成立するのは、どのお菓子も1人につき最大1個しか使えないという制約があるため、お菓子の種類ごとに独立して扱えるからです。
また、お菓子が多い順に考えることで、できるだけ多くの人に配れる可能性を広げることができます。
アルゴリズム
- 各お菓子の個数 \(C_i\) を降順にソートします(実はソートしなくても解けますが、直感的にわかりやすいため)。
- 各お菓子 \(i\) について、最大で \(\min(C_i, N)\) 人に配れると考え、合計を加算していきます。
- 合計が \(N \times K\) に達したら
Yesを出力し終了。すべて見終わっても足りなければNo。
計算量
- 時間計算量: \(O(M)\)
- 空間計算量: \(O(1)\) (入力を除く)
※ソートを行う場合、時間計算量は \(O(M \log M)\) になりますが、実際には必要ありません。
実装のポイント
- 各お菓子の配れる上限は \(\min(C_i, N)\) であること。
- 合計が \(N \times K\) を超えた時点で早期終了できるので、大きな入力でも高速に動作します。
- Python では
input()の代わりにsys.stdin.read()を使うことで、大量の入力を高速に読み込めます。
## ソースコード
```python
import sys
import heapq
def main():
import sys
input = sys.stdin.read
data = input().split()
N = int(data[0])
M = int(data[1])
K = int(data[2])
C = list(map(int, data[3:3+M]))
# 各お菓子の個数を降順にソートする
C.sort(reverse=True)
# 最大ヒープを用意する(Pythonでは最小ヒープなので負にして使う)
# 各メンバーが持てる残りの必要なお菓子の数を管理する
# 初期状態では、各メンバーがK個持つ必要がある
# しかし、N人がそれぞれK個必要なので、合計 N*K 個が必要
# それぞれの種類のお菓子を最大何人に配れるかを考える
# 貪欲法:多い順にお菓子を見て、各お菓子を最大限配る
# 各お菓子 i は C[i] 個あるので、最大 C[i] 人に配れる(1人1個まで)
# 全体で N 人の人に K 個ずつ配る必要がある → 合計 N*K 個必要
# 各お菓子を最大 min(C[i], N) 人に配ることができる(1人につき1個まで)
# しかし、より正確には、今持っている最も需要の高い(残り少ない)人に優先的に配るべき
# より効率的な方法:
# 各お菓子 i について、最大 min(C[i], N) 人に配れる
# つまり、合計で sum(min(C[i], N) for i in range(M)) 個配れる
# これが N*K 以上であれば OK
total = 0
for c in C:
total += min(c, N)
if total >= N * K:
print("Yes")
return
print("No")
if __name__ == "__main__":
main()
この解説は qwen3-coder-480b によって生成されました。
投稿日時:
最終更新: