D - Polyomino 解説 by Kiri8128

ビット演算による実装

この 問題 解説 の方法と同様、盤面を 2 進法で表された整数だと考えて処理すると、実装が簡単になり、並列計算の分だけ計算量も小さくなります。

本問では、前回の問題に比べ回転があるところの処理が難しくなっています。 公式解説 のように \(2\) 次元配列としてしても良いですが、並列計算を生かす方法もあります。具体的には、例えば、横向きのときは \(2\) 進法、縦向きのときは \(32\) 進法と思って入力を変換すると良いです。

(方針)

  • \(2\) 進法で考えます
  • 右端に番兵を \(1\) マスずつ付けて、盤面を横 \(5\) マス、縦 \(4\) マスの \(20\) マスを並べたひとつの \(20\) ビットの整数で表現することを考えます
  • 入力を回転させる必要があるので、受け取った直後に \(2\) 進法・ \(32\) 進法で変換します
  • 上下・左右を含む平行移動はすべてビットシフトで表現できます
  • 入力(を回転させたもの)の末尾の \(0\) を消した状態から、最大で \(18\) ビット左シフトすれば十分です
  • a の末尾の \(0\) を消したものは a // (a & -a) で計算できます
  • 全体を覆っていることは、盤面が \(507375\)\(=1+2+2^{2}+2^{3}+2^{5}+2^{6}+2^{7}+2^{8}+2^{10}+2^{11}+2^{12}+2^{13}+2^{15}+2^{16}+2^{17}+2^{18}\))と一致することを確認すれば良いです
  • \(2\) つが「重ならない」は、例えば a & b == 0 で表現できます(popcount で確認する方法もあります)

AC コード (PyPy3)

投稿日時:
最終更新: