【题解】ABC228G - Digits on Grid
给定一个 \(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;
}