AtCoder Beginner Contest 228 G Digits on Grid
?这啥啊,不会。
考虑行和列分别作为左部点和右部点建二分图(实际上这个建图只是辅助理解,不需要显式建图),每个左部点和每个右部点,边权为格子中的数。
容易想到一个 dp,设 \(f_{i, j}\) 为走了 \(i\) 步,当前在点 \(j\),走过的所有边权组成的不同整数的数量。但是你会发现根本没法做,因为不同的状态有可能包含相同的整数,很尴尬。
然后就是奇妙的部分了。更改状态为 \(f_{i, S}\) 表示走了 \(i\) 步,不同整数的数量,使得所有走过这些整数的路径的终点集合为 \(S\) 的方案数。注意到如果 \(S\) 不同,那走过的整数一定不同。因此这个状态设计是没问题的。
转移是平凡的。枚举下一步填的位,沿着边权为它的边走,即可得知终点集合。
注意到若 \(i\) 为偶数,\(S\) 为左部点集子集;若 \(i\) 为奇数,\(S\) 为右部点集子集。所以朴素实现的时间复杂度是 \(O(10N (2^H + 2^W) HW)\)。显然可以预处理一些东西做到更优,但是这个复杂度足以通过了。
code
// Problem: G - Digits on Grid
// Contest: AtCoder - TOYOTA SYSTEMS Programming Contest 2021(AtCoder Beginner Contest 228)
// URL: https://atcoder.jp/contests/abc228/tasks/abc228_g
// Memory Limit: 1024 MB
// Time Limit: 3000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include <bits/stdc++.h>
#define pb emplace_back
#define fst first
#define scd second
#define mems(a, x) memset((a), (x), sizeof(a))
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef double db;
typedef long double ldb;
typedef pair<ll, ll> pii;
const int maxn = 610;
const int maxm = (1 << 10) + 50;
const ll mod = 998244353;
ll n, m, K, a[15][15], f[maxn][maxm];
void solve() {
scanf("%lld%lld%lld", &n, &m, &K);
K <<= 1;
for (int i = 0; i < n; ++i) {
for (int j = 0; j < m; ++j) {
scanf("%1lld", &a[i][j]);
}
}
f[0][(1 << n) - 1] = 1;
for (int i = 1; i <= K; ++i) {
if (i & 1) {
for (int S = 1; S < (1 << n); ++S) {
if (!f[i - 1][S]) {
continue;
}
for (int d = 1; d <= 9; ++d) {
int T = 0;
for (int i = 0; i < n; ++i) {
if ((~S) & (1 << i)) {
continue;
}
for (int j = 0; j < m; ++j) {
if (a[i][j] == d) {
T |= (1 << j);
}
}
}
f[i][T] = (f[i][T] + f[i - 1][S]) % mod;
}
}
} else {
for (int S = 0; S < (1 << m); ++S) {
if (!f[i - 1][S]) {
continue;
}
for (int d = 1; d <= 9; ++d) {
int T = 0;
for (int j = 0; j < m; ++j) {
if ((~S) & (1 << j)) {
continue;
}
for (int i = 0; i < n; ++i) {
if (a[i][j] == d) {
T |= (1 << i);
}
}
}
f[i][T] = (f[i][T] + f[i - 1][S]) % mod;
}
}
}
}
ll ans = 0;
for (int S = 1; S < (1 << n); ++S) {
ans = (ans + f[K][S]) % mod;
}
printf("%lld\n", ans);
}
int main() {
int T = 1;
// scanf("%d", &T);
while (T--) {
solve();
}
return 0;
}