ABC166F を直感的なDFSで

直感的な、と書いていますが、計算が間に合うことは直感に反すると思います。

問題概要

F - Three Variables Game

非負整数の値をとる変数 A,B,C に対して、操作を  N 回行います。i 番目の操作は、長さ 2 の文字列 S_i によって表され、指定された 2 変数のうち一方を 1 増やし、他方を  1 減らすというものです。すべての操作が可能かどうか判定してください。さらに、可能なら手順をひとつ提示してください。

解答

最も直感的な解法は、操作ごとに二通りに分岐して、すべてのパターンを試すことでしょう。手順の提示を省略し、疑似コードで示します。

procedure dfs( i ) =
  if i > N then 成功
  foreach S_i の意味する操作 do
    if 操作が可能 then
      操作
      dfs( i + 1 )
      逆操作
dfs( 1 )

これでは間に合うわけがありません。O(2^N) 個もの状態を考慮することになります。

……というのは嘘で、これで十分間に合います。以下にざっくり示します。

正当性(なぜ速い?)

A=B=C=0 のとき、明らかに即座に終了します。A+B+C= 1 のとき、dfs(i) は高々 1 回しか dfs(i+1) を呼び出さないため、このDFSは時間計算量 O(N) で動作します。以下、A+B+C\ge 2 を仮定します。

操作ができないとき、すなわち dfs(i)dfs( i+1 ) を呼ばないとき1を考えます。たとえば操作 'AB' が与えられたときに、A=B=0 だったとします。

  • ひとつ前の状態がないとき、操作は不可能です。
  • ひとつ前の状態があるとき、ひとつ前の操作は確実に 'AC' か 'BC' であり、確実に A B1 減らしています。
    • ひとつ前の操作で C を減らすほうを選べる場合、そちらを選べば操作 'AB' は確実に可能です。
    • ひとつ前の操作で C を減らすほうを選べない場合、ひとつ前の状態は (A,B,C)=(1,0,0),(0,1,0) のどちらかです。A+B+C\ge 2 なのでありえません。

これをもとに考えると、各 i について dfs(i) が高々 2 回しか呼ばれないことがわかります2。よってこのDFSは時間計算量 O(N) で動作します。


  1. もちろん、成功して終了する場合を除きます。

  2. 論証に穴がある可能性は否定できませんが、存在するテストケースについては正しいです。この提出で確認しています。