ABC 232

A - QQ solver

問題

char で受けて '0' で引くということもできるが, iostream は条件に合うものを最大長マッチでとってくる(らしい)ので下のような書き方でも通る.

int a, b;
char x;
cin >> a >> x >> b;
cout << a*b << endl;

提出コード

C - Graph Isomorphism

問題

高橋くんの番号と青木くんの番号の対応関係 $N!$ 通りをすべて試して, グラフが一致すれば Yes, だめなら No.

提出コード

D - Weak Takahashi

問題

$(1, 1)$ から BFS してステップ数が最大となるものが答え

提出コード

E - Rook Path

問題

$H \times W$ のグリッドを下のような領域に分ける.

e_grid.png

$dp[k][i][j]$ を $k$ 回の操作のあとで領域 $S_{i,j}$ にいる場合の数とすると

※ 上記の説明の○通りは特定の領域の特定のマスからの移動の場合の数について述べている.

上の式を見ると連立方程式になっている. 次のように行列を使って表現することができる. $v_i(t)$ を時刻 $t$ における領域 $i$ ($i = 2a+b$, $S_{a,b}$) にある状態数, 遷移行列 $T = \begin{bmatrix}H+W-4 & W-1 & H-1 & 0 \\ 1 & H-2 & 0 & H-1 \\ 1 & 0 & W-2 & W-1 \\ 0 & 1 & 1 & 0\end{bmatrix}$ とすると $K$ 回後の操作のあとの状態ベクトル $\vec{v}(K)$ は $\vec{v}(K) = T^K \vec{v}(0)$ となる. $v_3(K)$ が問題の答えとなる.

$T^K$ の計算や高速冪乗計算の要領で高速に計算できる.

提出コード

F - Simple Operations on Sequence

問題

swap と数の増減の操作は独立なので操作の順番は結果に依存しない.

$A$ の並べ替えによってできた数列を $A^\prime$ とし, $A^\prime_i$ を $i = 1$ から順に決めていくことを考える.

$dp[i][S]$ を $i$ 番目までが確定しており, 1番目から $i$ 番目に含まれる数字の集合が $S = \{A^\prime_1, \cdots, A^\prime_i\}$ となるようなときの最小コストとする.

例:

$dp[2][\{A_3, A_7\}] = \min(A_3 A_7 ... \text{となるような swap のコスト} + \text{数の増減}, A_3 A_7 ... \text{となるような swap のコスト} + \text{数の増減})$.

$A_j$ $(j \notin S)$ を $i+1$ 番目に移動させ, $B_{i+1}$ と同じになるようにするためにかかるコストは

$dp[i+1][S \cup \{A_j\}] = dp[i][S] + (i+1 \text{と} A_j が今ある位置の距離) \times Y + \mathrm{abs}(A_j - B_{i+1})$

となる. ここで $dp[0][0] = 0$.

$(i+1 \text{と} A_j が今ある位置の距離)$ について考える. 今 $S$ を整数で表し $k$ 番目(0-index)の bit が立っているとき $A_{k+1} \in S$ とする. 例: $S = 00101 \rightarrow A_{1}, A_{3} \in S$.

$i$ 番目までの文字が決定したとき, $i+1 ~ N$ 番目の文字の位置関係はもとの数列の位置関係と同じであるから(バブルソートが安定なソートであることからもわかる) $A_j \notin S$ の位置と $i+1$ 番目の距離は, $S$ の整数表現を 0 bit 目から見ていき $j-1$ 番目までに含まれる 0 の個数と一致する.

例: $i = 2 \wedge S = 00101$ のとき, $A^\prime = A_1 A_3 A_2 A_4 A_5$ or $A^\prime = A_3 A_1 A_2 A_4 A_5$ となり, $j = 2$ のとき $S$ の $j - 1 = 1$ 番目までに含まれる 0 の個数は 0 個のため $A_2$ の位置と $i+1$ の差は 0, 同様にして $j = 4$ のとき $S$ の $j - 1 = 3$ 番目までに含まれる 0 の個数は 1 個のため $A_4$ の位置と $i+1$ の差は1. … となる.

以上のことを踏まえると下記のようになり, $O(N^2 2^N)$ で解ける.

dp[0][0] = 0;
rep2(i, 1, N + 1) {
    rep(S, 1 << N) {
        rep(j, N) {
            if ((S & (1 << j)) > 0)
                continue;
            chmin(dp[i][S | (1 << j)], dp[i - 1][S] + get(S, j) * Y + abs(A[j + 1] - B[i]) * X);
        }
    }
}

提出コード

上記のコードでは $i$ でループを回しているが, $S$ に立っている bit 数からも求めることができるので以下のようにもかける. このときの計算量は $O(N2^N)$.

vector<ll> dp(1 << N, INF);
dp[0] = 0;
rep(S, 1 << N) {
    rep(j, N) {
        if ((S & (1 << j)) > 0)
            continue;
        ll i = __builtin_popcountll(S | (1 << j));
        chmin(dp[S | (1 << j)], dp[S] + get(S, j) * Y + abs(A[j + 1] - B[i]) * X);
    }
}

提出コード