【題解】ABC228G - Digits on Grid
阿新 • • 發佈:2021-12-02
給定一個 \(H\times W\) 的數字矩陣,一共走 \(2N\) 步,任選一個起點,奇數步可以移動到同行的一個點,偶數步移動到同列的一個點,將路徑上的數記錄下來得到一個長度為 \(2N\) 的序列(不包括起點),問有多少種可能的序列。
觀察到行數和列數很小,考慮可以狀態壓縮。
經過思考後我們可以設計一個很妙的狀態,\(f[i][S]\) 表示走了 \(i\) 步,結束時在集合 \(S\) 中的列/行,有多少種序列。
顯然有初始狀態 \(f[0][2^{H} - 1] = 1\),並且如果 \(S\) 不同,那麼兩個序列一定不同,可以分開轉移。
那麼對於 \(S\) 相同的序列,我們列舉後面接的數是什麼,然後根據這個數推出可以到達的行。
直接做是 \(\mathcal{O}(NHW(2^H+2^W))\),預處理後可以做到 \(\mathcal{O}((N+HW)(2^H+2^W))\)。
#define N 11 int n, m, k, a[N][N], f[2][1 << N], u[1 << N][N], v[1 << N][N]; char s[N]; int main() { read(n), read(m), read(k); rp(i, n){ scanf("%s", s + 1); rp(j, m)a[i][j] = s[j] - '0'; } int p = (1 << n) - 1, q = (1 << m) - 1; rep(s, 1, p)rp(i, n)if((s >> (i - 1)) & 1)rp(j, m)u[s][a[i][j]] |= 1 << (j - 1); rep(s, 1, q)rp(j, m)if((s >> (j - 1)) & 1)rp(i, n)v[s][a[i][j]] |= 1 << (i - 1); f[0][p] = 1; rp(T, k){ memset(f[1], 0, sizeof(f[1])); rp(s, p) rep(i, 0, 9)ad(f[1][u[s][i]], f[0][s]); memset(f[0], 0, sizeof(f[0])); rp(s, q) rep(i, 0, 9)ad(f[0][v[s][i]], f[1][s]); } int ans = 0; rep(j, 1, p)ad(ans, f[0][j]); printf("%d\n", ans); return 0; }