/
実行時間制限: 2 sec / メモリ制限: 1024 MiB
ストーリー
魔王高橋くんのもとに、勇者青木くんが魔王城へ近づいているとの知らせが入った。
魔王は、勇者が玉座へ到達するまでの時間を少しでも稼ぐため、城内に連動式の扉とスイッチを設置して改造することにした。
ただし、魔王軍には勇者のスパイが潜入しているため、改造計画は勇者に筒抜けである。 さらに勇者は非常に賢く、玉座へ到達可能であれば、可能な限り少ない行動回数でたどり着いてしまう。
あなたは魔王の優秀な部下として、それでもなお勇者をできるだけ長く足止めできるような改造計画を立ててほしい。

問題文
N\times N マスの魔王城がある。 一番左上のマスの座標を (0,0) とし、そこから下方向に i マス、右方向に j マス進んだ先のマスの座標を (i,j) とする。
各マスは空きマス . または障害物 # のいずれかである。
また、N\times N の範囲外はすべて障害物であるとみなす。
マス (0,0) には入口があり、マス (N-1,N-1) には玉座がある。 これらのマスはいずれも空きマスである。
あなたは勇者が侵入してくる前に、城内に 扉 と スイッチ を設置できる。
扉
扉には 0,1,\ldots,2K-1 の 2K 個の 型 がある。 以降、型 g の扉を単に 扉 g と呼ぶ。
扉は、上下左右に隣接する 2 マスの間に設置でき、合計で最大 M 枚まで設置できる。 同じ 2 マスの間に設置できる扉は高々 1 枚である。 同じ型の扉を複数枚設置してもよい。
スイッチ
スイッチには 0,1,\ldots,K-1 の K 個の 種類 がある。 以降、種類 k のスイッチを単に スイッチ k と呼ぶ。
スイッチは各マスに 1 つまで設置できる。 同じ種類のスイッチを異なるマスに複数個設置してもよい。 また、1 つも設置されない種類のスイッチがあってもよい。 入口 (0,0) や玉座 (N-1,N-1) にもスイッチを設置してよい。
扉とスイッチの連動
各 k=0,1,\ldots,K-1 について、扉 2k と扉 2k+1 はスイッチ k によって制御される。 同じ型の扉はすべて同じ開閉状態を共有する。
初期状態では、扉 2k は開いており、扉 2k+1 は閉じている。
スイッチ k が押されるたびに、扉 2k と扉 2k+1 の開閉状態が入れ替わる。 すなわち、スイッチ k が押された回数が偶数回である状態では、扉 2k が開き、扉 2k+1 が閉じている。 スイッチ k が押された回数が奇数回である状態では、扉 2k が閉じ、扉 2k+1 が開いている。
障害物マスとの間に扉を設置してもよいが、そのような扉を通る移動はできない。 障害物マスにスイッチを設置してもよいが、そのようなスイッチは押すことができない。
勇者の行動
城の改造を終えると、勇者が入口 (0,0) から侵入してくる。 勇者は毎ターン、以下の 2 種類の行動から 1 つを選んで実行できる。
- 上下左右に隣接する空きマスへ移動する。ただし、現在いるマスと移動先のマスの間に扉があり、かつその扉が閉じている場合、その方向へは移動できない。
- 現在いるマスにスイッチがある場合、そのスイッチを押す。
現在いるマスにスイッチがある場合でも、勇者は必ずしもそのスイッチを押す必要はない。 スイッチを押さずに隣接マスへ移動してもよい。
勇者は、あなたが設置した扉とスイッチの配置をすべて知っている。 玉座へ到達可能であるならば、勇者は可能な限り少ない行動回数で玉座に到達する。
あなたの目的は、勇者が入口から玉座へ到達するために必要な最小の行動回数をできるだけ大きくすることである。
補足: 勇者の最小行動回数について
出力された改造計画に対する最小行動回数 T は、状態を「現在位置」と「各スイッチ k について、スイッチ k が押された回数の偶奇」の組として幅優先探索を行うことで計算できる。
現在位置は高々 N^2 通りであり、各スイッチの状態は K ビットで表せるため 2^K 通りである。 したがって、T の計算は O(2^K N^2) 時間で可能である。
以下は python による最小行動回数計算の実装例である。
from collections import deque
def calc_T(N, K, c, door_h, door_v, switch):
"""
N: 盤面サイズ
K: スイッチの種類数
c: マップ。c[i][j] は '.' または '#'
door_h: 上下方向の扉。door_h[i][j] は (i,j) と (i+1,j) の間の扉の型。扉なしは -1
door_v: 左右方向の扉。door_v[i][j] は (i,j) と (i,j+1) の間の扉の型。扉なしは -1
switch: switch[i][j] はマス (i,j) に置かれたスイッチの種類。スイッチなしは -1
返り値:
入口 (0,0) から玉座 (N-1,N-1) へ到達するための最小行動回数。
到達不能な場合は 0 を返す。
"""
def is_open(g, mask):
"""型 g の扉が、状態 mask において開いているかを返す。"""
if g == -1:
return True
k = g // 2
return ((mask >> k) & 1) == (g & 1)
dist = [[[-1] * N for _ in range(N)] for _ in range(1 << K)]
dist[0][0][0] = 0
que = deque()
que.append((0, 0, 0))
while que:
mask, i, j = que.popleft()
d = dist[mask][i][j]
if (i, j) == (N - 1, N - 1):
return d
# 行動 1: 隣接する空きマスへ移動する
for di, dj in [(-1, 0), (1, 0), (0, -1), (0, 1)]:
ni, nj = i + di, j + dj
if not (0 <= ni < N and 0 <= nj < N):
continue
if c[ni][nj] == '#':
continue
if di == 1:
g = door_h[i][j]
elif di == -1:
g = door_h[ni][nj]
elif dj == 1:
g = door_v[i][j]
else:
g = door_v[ni][nj]
if not is_open(g, mask):
continue
if dist[mask][ni][nj] == -1:
dist[mask][ni][nj] = d + 1
que.append((mask, ni, nj))
# 行動 2: 現在のマスのスイッチを押す
s = switch[i][j]
if s != -1:
nmask = mask ^ (1 << s)
if dist[nmask][i][j] == -1:
dist[nmask][i][j] = d + 1
que.append((nmask, i, j))
return 0
得点
出力した改造計画に対して、勇者が入口 (0,0) から玉座 (N-1,N-1) へ有限回の行動で到達可能である場合、そのために必要な最小の行動回数を T とする。 このとき、以下の得点が得られる。
\[ \mathrm{round}\left(10^6\times \log_2 \frac{T}{N}\right) \]
勇者が玉座へ到達不能である場合、得点は 1 点となる。
合計で 150 個のテストケースがあり、各テストケースの得点の合計が提出の得点となる。 一つ以上のテストケースで不正な出力や制限時間超過をした場合、提出全体の判定が WA や TLE となる。 コンテスト時間中に得た最高得点で最終順位が決定され、コンテスト終了後のシステムテストは行われない。 同じ得点を複数の参加者が得た場合、提出時刻に関わらず同じ順位となる。
入力
入力は以下の形式で標準入力から与えられる。
N M K
c_0
\vdots
c_{N-1}
- すべてのテストケースにおいて、盤面サイズ N は 20 に固定されている。
- すべてのテストケースにおいて、設置できる扉の最大枚数 M は 50 に固定されている。
- すべてのテストケースにおいて、スイッチの種類数 K は 10 に固定されている。
- c_i は長さ N の文字列であり、その j 文字目 c_{i,j} はマス (i,j) が空きマスの場合
.、障害物の場合#である。 - c_{0,0}=c_{N-1,N-1}=
.である。 - すべての空きマスは、空きマスのみを通って入口 (0,0) から到達可能であることが保証されている。
出力
まず、設置する扉の枚数を D として、以下の形式で扉の配置を標準出力へ出力せよ。
D
d_0 i_0 j_0 g_0
\vdots
d_{D-1} i_{D-1} j_{D-1} g_{D-1}
a 番目の扉は、向き d_a、座標 (i_a,j_a)、扉の型 g_a によって表される。
- d_a=0 の場合、マス (i_a,j_a) とマス (i_a+1,j_a) の間に扉 g_a を設置する。
- d_a=1 の場合、マス (i_a,j_a) とマス (i_a,j_a+1) の間に扉 g_a を設置する。
出力は以下の条件を満たさなければならない。
- 0\leq D\leq M
- 各扉について、d_a は 0 または 1 である。
- 各扉について、0\leq g_a<2K を満たす。
- d_a=0 の場合、0\leq i_a<N-1 かつ 0\leq j_a<N を満たす。
- d_a=1 の場合、0\leq i_a<N かつ 0\leq j_a<N-1 を満たす。
- 同じ 2 マスの間に複数の扉を設置してはならない。
続いて、設置するスイッチの個数を S として、スイッチの配置を以下の形式で出力せよ。
S
p_0 q_0 s_0
\vdots
p_{S-1} q_{S-1} s_{S-1}
b 番目のスイッチは、マス (p_b,q_b) に設置され、その種類は s_b である。
出力は以下の条件を満たさなければならない。
- 0\leq S\leq N^2
- 各スイッチについて、0\leq p_b,q_b<N を満たす。
- 各スイッチについて、0\leq s_b<K を満たす。
- 同じマスに複数のスイッチを設置してはならない。
入力生成方法
N=20, M=50, K=10 で固定である。
まず、すべてのマスが空きマスである状態から開始する。 (0,0) と (N-1,N-1) 以外の N^2-2 マスをランダムな順に並べ、順に以下の処理を行う。
対象のマスを (i,j) とする。 マス (i,j) の上下左右 4 マスのうち、障害物であるマスの個数が 3 以上であれば、このマスに対する処理をスキップする。 ただし、N\times N の範囲外は障害物として数える。 そうでない場合、マス (i,j) を一時的に障害物に変更する。 この変更によって空きマス全体が非連結になった場合、マス (i,j) を空きマスに戻す。 非連結にならなかった場合は、マス (i,j) を障害物にしたままにする。
次に、すべての障害物マスをランダムな順に並べ、順に以下の処理を行う。
対象のマスを (i,j) とする。 マス (i,j) の上下左右 4 マスに空きマスが 1 つ以上ある場合、マス (i,j) を空きマスに変更する。 障害物マスを空きマスに変更した回数が N 回に達した時点で、この処理を終了する。
ツール(入力ジェネレータ・ビジュアライザ)
- Web版: ローカル版より高性能でアニメーション表示が可能です。
- ローカル版: 使用するにはRust言語のコンパイル環境をご用意下さい。
- Windows用のコンパイル済みバイナリ: Rust言語の環境構築が面倒な方は代わりにこちらをご利用下さい。
コンテスト期間中に、ビジュアライズ結果の共有や、解法・考察に関する言及は禁止されています。ご注意下さい。
Story
Demon King Takahashi has received word that the hero Aoki is approaching his castle.
To buy as much time as possible before the hero reaches the throne, the Demon King has decided to renovate the castle by installing linked doors and switches.
However, since the Demon King's army has been infiltrated by a spy working for the hero, the renovation plan is completely known to him. Moreover, the hero is extremely clever, and if the throne is reachable, he will reach it using as few actions as possible.
As one of the Demon King's most capable subordinates, you are asked to devise a renovation plan that still delays the hero for as long as possible.

Problem Statement
There is a Demon King's castle consisting of N\times N cells. Let (0,0) be the coordinates of the top-left cell, and let (i,j) denote the cell that is i cells downward and j cells to the right from there.
Each cell is either an empty cell . or an obstacle #.
All cells outside the N\times N grid are regarded as obstacles.
Cell (0,0) contains the entrance, and cell (N-1,N-1) contains the throne. Both of these cells are empty cells.
Before the hero enters the castle, you may install doors and switches inside the castle.
Doors
There are 2K types of doors, numbered 0,1,\ldots,2K-1. Hereafter, a door of type g will simply be called door g.
A door can be installed between two orthogonally adjacent cells, and at most M doors may be installed in total. At most one door can be installed between the same two cells. Multiple doors of the same type may be installed.
Switches
There are K kinds of switches, numbered 0,1,\ldots,K-1. Hereafter, a switch of kind k will simply be called switch k.
At most one switch can be installed in each cell. Multiple switches of the same kind may be installed in different cells. There may also be kinds of switches that are not installed at all. Switches may also be installed at the entrance (0,0) and the throne (N-1,N-1).
Linkage Between Doors and Switches
For each k=0,1,\ldots,K-1, door 2k and door 2k+1 are controlled by switch k. All doors of the same type share the same open/closed state.
Initially, door 2k is open, and door 2k+1 is closed.
Each time switch k is pressed, the open/closed states of door 2k and door 2k+1 are swapped. That is, when switch k has been pressed an even number of times, door 2k is open and door 2k+1 is closed. When switch k has been pressed an odd number of times, door 2k is closed and door 2k+1 is open.
A door may be installed between a cell and an obstacle cell, but movement through such a door is impossible. A switch may be installed on an obstacle cell, but such a switch cannot be pressed.
Hero's Actions
After the renovation of the castle is complete, the hero enters from the entrance (0,0). On each turn, the hero may choose and perform one of the following two actions.
- Move to an orthogonally adjacent empty cell. However, if there is a door between the current cell and the destination cell and that door is closed, the hero cannot move in that direction.
- If there is a switch on the current cell, press that switch.
Even if there is a switch on the current cell, the hero does not necessarily have to press it. The hero may move to an adjacent cell without pressing the switch.
The hero knows the entire placement of the doors and switches you installed. If the throne is reachable, the hero reaches the throne using as few actions as possible.
Your objective is to maximize the minimum number of actions required for the hero to reach the throne from the entrance.
Supplement: Minimum Number of Actions for the Hero
For a given output renovation plan, the minimum number of actions T can be computed by performing a breadth-first search whose state consists of the current position and, for each switch k, the parity of the number of times switch k has been pressed.
There are at most N^2 possible current positions, and the states of the switches can be represented by K bits, giving 2^K possibilities. Therefore, T can be computed in O(2^K N^2) time.
The following is an example implementation in python for computing the minimum number of actions.
from collections import deque
def calc_T(N, K, c, door_h, door_v, switch):
"""
N: board size
K: number of switch kinds
c: map. c[i][j] is either '.' or '#'
door_h: doors in the vertical direction. door_h[i][j] is the type of the door between (i,j) and (i+1,j). -1 if there is no door
door_v: doors in the horizontal direction. door_v[i][j] is the type of the door between (i,j) and (i,j+1). -1 if there is no door
switch: switch[i][j] is the kind of the switch placed on cell (i,j). -1 if there is no switch
Returns:
The minimum number of actions required to reach the throne (N-1,N-1) from the entrance (0,0).
Returns 0 if it is unreachable.
"""
def is_open(g, mask):
"""Returns whether the door of type g is open in state mask."""
if g == -1:
return True
k = g // 2
return ((mask >> k) & 1) == (g & 1)
dist = [[[-1] * N for _ in range(N)] for _ in range(1 << K)]
dist[0][0][0] = 0
que = deque()
que.append((0, 0, 0))
while que:
mask, i, j = que.popleft()
d = dist[mask][i][j]
if (i, j) == (N - 1, N - 1):
return d
# Action 1: Move to an adjacent empty cell
for di, dj in [(-1, 0), (1, 0), (0, -1), (0, 1)]:
ni, nj = i + di, j + dj
if not (0 <= ni < N and 0 <= nj < N):
continue
if c[ni][nj] == '#':
continue
if di == 1:
g = door_h[i][j]
elif di == -1:
g = door_h[ni][nj]
elif dj == 1:
g = door_v[i][j]
else:
g = door_v[ni][nj]
if not is_open(g, mask):
continue
if dist[mask][ni][nj] == -1:
dist[mask][ni][nj] = d + 1
que.append((mask, ni, nj))
# Action 2: Press the switch on the current cell
s = switch[i][j]
if s != -1:
nmask = mask ^ (1 << s)
if dist[nmask][i][j] == -1:
dist[nmask][i][j] = d + 1
que.append((nmask, i, j))
return 0
Scoring
For the renovation plan you output, if the hero can reach the throne (N-1,N-1) from the entrance (0,0) in a finite number of actions, let T be the minimum number of actions required to do so. In this case, you will obtain the following score.
\[ \mathrm{round}\left(10^6\times \log_2 \frac{T}{N}\right) \]
If the hero cannot reach the throne, the score will be 1.
There are 150 test cases, and the score of a submission is the total score for each test case. If your submission produces an illegal output or exceeds the time limit for some test cases, the submission itself will be judged as WA or TLE , and the score of the submission will be zero. The highest score obtained during the contest will determine the final ranking, and there will be no system test after the contest. If more than one participant gets the same score, they will be ranked in the same place regardless of the submission time.
Input
Input is given from Standard Input in the following format.
N M K
c_0
\vdots
c_{N-1}
- In all test cases, the board size N is fixed to 20.
- In all test cases, the maximum number of doors that can be installed, M, is fixed to 50.
- In all test cases, the number of switch kinds, K, is fixed to 10.
- c_i is a string of length N, and its j-th character c_{i,j} is
.if cell (i,j) is an empty cell and#if it is an obstacle. - c_{0,0}=c_{N-1,N-1}=
.. - It is guaranteed that every empty cell is reachable from the entrance (0,0) by passing only through empty cells.
Output
First, let D be the number of doors to install, and output the placement of the doors to Standard Output in the following format.
D
d_0 i_0 j_0 g_0
\vdots
d_{D-1} i_{D-1} j_{D-1} g_{D-1}
The a-th door is represented by its direction d_a, coordinates (i_a,j_a), and door type g_a.
- If d_a=0, install door g_a between cell (i_a,j_a) and cell (i_a+1,j_a).
- If d_a=1, install door g_a between cell (i_a,j_a) and cell (i_a,j_a+1).
The output must satisfy the following conditions.
- 0\leq D\leq M
- For each door, d_a is either 0 or 1.
- For each door, 0\leq g_a<2K holds.
- If d_a=0, 0\leq i_a<N-1 and 0\leq j_a<N hold.
- If d_a=1, 0\leq i_a<N and 0\leq j_a<N-1 hold.
- Do not install multiple doors between the same two cells.
Then, let S be the number of switches to install, and output the placement of the switches in the following format.
S
p_0 q_0 s_0
\vdots
p_{S-1} q_{S-1} s_{S-1}
The b-th switch is installed on cell (p_b,q_b), and its kind is s_b.
The output must satisfy the following conditions.
- 0\leq S\leq N^2
- For each switch, 0\leq p_b,q_b<N holds.
- For each switch, 0\leq s_b<K holds.
- Do not install multiple switches on the same cell.
Input Generation
N=20, M=50, and K=10 are fixed.
First, start with all cells being empty cells. Arrange the N^2-2 cells other than (0,0) and (N-1,N-1) in random order, and process them in that order as follows.
Let the target cell be (i,j). If at least 3 of the 4 orthogonally adjacent cells of cell (i,j) are obstacle cells, skip the process for this cell. Cells outside the N\times N grid are counted as obstacles. Otherwise, temporarily change cell (i,j) into an obstacle. If this change makes all empty cells disconnected, change cell (i,j) back into an empty cell. Otherwise, leave cell (i,j) as an obstacle.
Next, arrange all obstacle cells in random order, and process them in that order as follows.
Let the target cell be (i,j). If at least one of the 4 orthogonally adjacent cells of cell (i,j) is an empty cell, change cell (i,j) into an empty cell. Once the number of times an obstacle cell has been changed into an empty cell reaches N, terminate this process.
Tools (Input generator and visualizer)
- Web version: This is more powerful than the local version providing animations.
- Local version: You need a compilation environment of Rust language.
- Pre-compiled binary for Windows: If you are not familiar with the Rust language environment, please use this instead.
Please be aware that sharing visualization results or discussing solutions/ideas during the contest is prohibited.