AtCoder Grand Contest 031: C - Differ by 1 Bit
問題
$A, B$ が与えられる。 次のような $\sigma \in \mathfrak{S} _ {2^N-1}$ の存在を判定し、存在するなら構成せよ。
- $\sigma(0) = A$
- $\sigma(2^N-1) = B$
- $\forall i \lt 2^N-1.~ \mathrm{popcount}(\sigma(i) \oplus \sigma(i+1)) = 1$
解法
$A = 0$ かつ $B = 2^k - 1$ と仮定してよい。 グレイコードまずそのまま作り、これを 2-opt のようにして変形すればよい。 計算量は不明だが $O(N^2 2^N)$ ぐらいで間に合う。 非想定ぽい。
考察過程
- それぞれに排他的論理和をして $(A, B) \gets (0, A \oplus B)$ と更新してよさそう (簡単化)
- 条件はグレイコードみたいになってる (知識)
- $\mathrm{popcount}(B) = 1$ なら自明 (部分問題)
- ちょうど $1$ bit 変わるので $\mathrm{popcount}(B)$ は奇数でなければならない (不変量) (必要条件)
- この必要条件はたぶん十分条件になってる (推測)
- 「$0$ から始まるグレイコードのような系列であって $B$ で終わるものを構成せよ」を解けばよい (帰着)
- グレイコードの末尾をいくつか反転させることで末尾を操作できないか (推測) (嘘)
- 「$0$ から始まるグレイコードのような系列であって奇数 $k$ に対し $2^k-1$ で終わるものを構成せよ」を解けばよい (帰着)
- 現在の末尾が $00001$ で、これを $00111$ にしたいとする。 $00111$ の前後に $00011$ か $00111$ があれば 2-opt のように継ぎ換えてよい。前後が $01111$ と $10111$ の場合は詰みだが、他に $11001$ への遷移とかを試せばよい。 $11111$ は代替を持たないが、最大なのでそういう問題はない。 (嘘)
- 嘘だったけど乱択で焼きなましぽく上手く誤魔化したら通った (終)
バグ
(k << 1) - 1
をb
に組み換えるようなことをしたくて 2 重ループを回したときに嘘のi < j
を仮定してしまった! ! (x & (1 << i) == ! ! (x & (1 << j)
とすべきところで(x & (1 << i) == (x & (1 << j)
1 << n
のつもりでn << 1
と書く
感想
結局乱択で誤魔化したので実質解けてない。 やたらバグらせた。ブランクを感じる。
想定解は $N$ に関する帰納法。 特に任意の $A, B$ に対して成立するように強めたもの。 初手の簡単化のあたりがまずかったということらしい。