公式
A - 図鑑コンプリート / Encyclopedia Completion 解説 by admin
Claude 4.5 Opus概要
見つけた花の中から、各品種について最初に見つけたものだけを選び、その枚数と品種番号の合計を求める問題です。
考察
この問題のポイントは「同じ品種番号の花が複数回出てきたとき、最初の1回だけを採用する」という点です。
例えば、花の品種番号が [3, 1, 2, 1, 3, 4] の順で見つかった場合を考えてみましょう:
- 1番目: 品種3 → 初めて見た → 採用
- 2番目: 品種1 → 初めて見た → 採用
- 3番目: 品種2 → 初めて見た → 採用
- 4番目: 品種1 → 既に見た → 除外
- 5番目: 品種3 → 既に見た → 除外
- 6番目: 品種4 → 初めて見た → 採用
結果:枚数は \(4\) 枚、品種番号の合計は \(3 + 1 + 2 + 4 = 10\) となります。
なぜ集合(set)を使うのか?
「既に見たかどうか」を効率的に判定する必要があります。
- 素朴な方法(リストで管理): 毎回リストを全て走査して確認 → 1回の判定に \(O(N)\) かかり、全体で \(O(N^2)\)
- 集合(set)を使う方法: 集合への追加・検索は平均 \(O(1)\) → 全体で \(O(N)\)
\(N\) が最大 \(2 \times 10^5\) なので、\(O(N^2)\) では間に合わない可能性がありますが、\(O(N)\) なら十分高速です。
アルゴリズム
- 「既に見た品種番号」を管理するための集合
seenを用意する - 花の枚数をカウントする変数
countと、品種番号の合計を保持する変数totalを \(0\) で初期化 - 花を見つけた順に1つずつ処理:
- その品種番号が
seenに含まれていなければ:seenにその品種番号を追加countを \(1\) 増やすtotalにその品種番号を加える
- 既に
seenに含まれていれば何もしない(重複なので除外)
- その品種番号が
- 最終的な
countとtotalを出力
計算量
- 時間計算量: \(O(N)\)
- 各花について、集合への追加・検索は平均 \(O(1)\) で行える
- \(N\) 個の花を順番に処理するので、全体で \(O(N)\)
- 空間計算量: \(O(\min(N, 100))\)
- 集合
seenには最大でも100種類(品種番号は1〜100)しか入らない - 実質的には \(O(1)\)(定数)とも言える
- 集合
実装のポイント
Pythonの
setは、要素の追加(add)と存在確認(in)が平均 \(O(1)\) で行えるため、このような「重複を除く」処理に最適if s not in seen:で「まだ見ていない品種か」を判定し、条件を満たす場合のみカウントと合計を更新する品種番号の範囲が1〜100と小さいため、配列(サイズ101のリスト)を使って
seen[s] = Trueのように管理する方法でも実装可能ソースコード
N = int(input())
S = list(map(int, input().split()))
seen = set()
count = 0
total = 0
for s in S:
if s not in seen:
seen.add(s)
count += 1
total += s
print(count, total)
この解説は claude4.5opus によって生成されました。