CF1237F Balanced Domino Placements
题读错了。。。
对于一个骨牌的每个格子,不能有其他骨牌的格子和它在同一列或同一行。
那么行列分开单独考虑。
- 设 (f_{i,j}) 为前 (i) 行放了几个占了两个格子的。
- 设 (g_{i,j}) 为前 (i) 列放了几个占了两个格子的。
(egin{cases} f_{i,j} = f_{i-1,j} + f_{i-2,j-1} cdot [2 le i &j &!row_i&!row_{i-1}] \ g_{i,j} = g_{i-1,j} + g_{i-2, j-1} cdot [2 le i &j& !col_i &!col_{i-1} ]end{cases})
最后答案就是 (f_{N,i} cdot g_{M,j} cdot C_{sumx - 2 cdot i}^{j} cdot C_{sumy - 2 cdot j}^i cdot i! cdot j!)
/*
Name: 1237F
Author: Gensokyo_Alice
Date: 2020/11/16
Description:
*/
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <vector>
#include <queue>
#include <stack>
#include <cmath>
#include <ctime>
#include <map>
#include <set>
using namespace std;
typedef long long ll;
const ll MAXN = 4e3+10, MOD = 998244353;
ll N, M, K, col[MAXN], row[MAXN], sumx, sumy, fac[MAXN], inv[MAXN], ans, f[MAXN][MAXN], g[MAXN][MAXN];
ll P(ll, ll);
int main() {
scanf("%lld%lld%lld", &N, &M, &K);
for (ll x, y, xx, yy, i = 1; i <= K; i++) {
scanf("%lld%lld%lld%lld", &x, &y, &xx, &yy);
col[y] = col[yy] = row[x] = row[xx] = 1;
}
inv[0] = inv[1] = fac[0] = fac[1] = 1;
for (ll i = 2, k = MAXN - 10; i <= k; i++) inv[i] = inv[MOD % i] * (MOD - MOD / i) % MOD, fac[i] = fac[i-1] * i % MOD;
for (ll i = 1, k = MAXN - 10; i <= k; i++) (inv[i] *= inv[i-1]) %= MOD;
for (ll i = 1; i <= N; i++) sumx += !row[i];
for (ll i = 1; i <= M; i++) sumy += !col[i];
f[0][0] = g[0][0] = 1;
for (ll i = 1; i <= N; i++)
for (ll j = 0; 2 * j <= sumx; j++)
f[i][j] = (f[i-1][j] + ((j && i >= 2 && !row[i] && !row[i-1]) ? f[i-2][j-1] : 0)) % MOD;
for (ll i = 1; i <= M; i++)
for (ll j = 0; 2 * j <= sumy; j++)
g[i][j] = (g[i-1][j] + ((j && i >= 2 && !col[i] && !col[i-1]) ? g[i-2][j-1] : 0)) % MOD;
for (ll i = 0; i * 2 <= sumx; i++)
for (ll j = 0; j * 2 <= sumy; j++)
(ans += f[N][i] * g[M][j] % MOD * P(j, sumx - 2 * i) % MOD * P(i, sumy - 2 * j) % MOD) %= MOD;
printf("%lld", ans);
return 0;
}
ll P(ll m, ll n) {
if (m > n) return 0;
return fac[n] * inv[n-m] % MOD;
}