C - 化学反応シミュレーション / Chemical Reaction Simulation Editorial by admin Editorial for printing
Claude 4.6 Opus (Thinking)概要
元素を1つずつ試験管(スタック)に投入し、スタックの一番上の元素と新しい元素が反応パターンに一致すれば両方消滅する、という操作をシミュレーションして最終的な試験管の中身を求める問題です。
考察
重要な気づき:スタックで素直にシミュレーションできる
問題文をよく読むと、以下の2点がポイントです。
- 試験管はスタック構造:新しい元素は常に一番上(末尾)に積まれる。
- 連鎖反応は起きない:1回の投入で起きる消滅は高々1回。消滅後に新たに露出した末尾との再チェックは行わない。
この2点のおかげで、問題は「スタックに対して push するか、条件を満たせば pop するか」という単純なシミュレーションに帰着します。
具体例で確認
例えば、\(S = \) ABBA、反応パターンが \((A, B)\) と \((B, A)\) の場合:
| 投入文字 | スタック状態(操作前) | 判定 | スタック状態(操作後) |
|---|---|---|---|
| A | [] |
空なので push | [A] |
| B | [A] |
\((A, B)\) が反応パターン → pop | [] |
| B | [] |
空なので push | [B] |
| A | [B] |
\((B, A)\) が反応パターン → pop | [] |
最終結果は空なので EMPTY を出力します。
素朴なアプローチで十分か?
各文字について「スタック末尾との反応チェック」を行いますが、反応パターンの検索をどう実装するかが鍵です。反応パターンは最大 \(676\) 個(\(26 \times 26\))しかないので、集合(ハッシュセット)に格納すれば \(O(1)\) で判定できます。よって全体で \(O(N)\) となり、\(N \leq 10^6\) でも十分高速です。
アルゴリズム
- 前処理:\(M\) 個の反応パターン \((X_k, Y_k)\) をハッシュセット(Pythonの
set)に格納する。 - シミュレーション:文字列 \(S\) を先頭から1文字ずつ処理する。
- スタックが空でなく、
(スタック末尾, 現在の文字)が反応パターンに含まれる場合 → スタックから末尾を削除(pop)。 - そうでなければ → 現在の文字をスタックに追加(push)。
- スタックが空でなく、
- 出力:スタックが空なら
EMPTY、そうでなければスタックの中身を連結して出力する。
計算量
- 時間計算量: \(O(N + M)\)
- 反応パターンの読み込みに \(O(M)\)、文字列の各文字に対するスタック操作と反応判定がそれぞれ \(O(1)\) で合計 \(O(N)\)。
- 空間計算量: \(O(N + M)\)
- スタックに最大 \(O(N)\) 文字、反応パターンのセットに \(O(M)\) エントリを格納。
実装のポイント
高速な入力:\(N\) が最大 \(10^6\) と大きいため、Pythonでは
sys.stdin.buffer.read()でまとめて読み込むことで入出力のオーバーヘッドを抑えています。反応パターンの格納方法:
setにタプル(X, Y)を入れることで、\(O(1)\) のルックアップが可能です。反応パターンには向きがある(\((X, Y)\) と \((Y, X)\) は別物)点に注意が必要です。連鎖反応がないことの確認:問題文に「消滅が起きた後、新たに露出した末尾に対して再度反応チェックを行うことはない」と明記されているため、1回の投入につき判定は1回で済みます。もしこの条件がなければ、pop 後にさらにループで再チェックする必要がありますが、本問ではそれは不要です。
ソースコード
import sys
def main():
input_data = sys.stdin.buffer.read().decode()
tokens = input_data.split()
idx = 0
N = int(tokens[idx]); idx += 1
M = int(tokens[idx]); idx += 1
S = tokens[idx]; idx += 1
react = set()
for _ in range(M):
X = tokens[idx]; idx += 1
Y = tokens[idx]; idx += 1
react.add((X, Y))
stack = []
for ch in S:
if stack and (stack[-1], ch) in react:
stack.pop()
else:
stack.append(ch)
if stack:
print(''.join(stack))
else:
print('EMPTY')
main()
この解説は claude4.6opus-thinking によって生成されました。
posted:
last update: