Loading

【题解】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;
}
posted @ 2021-12-02 21:30  7KByte  阅读(156)  评论(0编辑  收藏  举报