标签:include bit amp c++ ace else 实现 pac clu
求出所有可能棋盘的不经过任意障碍的方案数之和。
考虑容斥,对于一条钦定经过 \(k\) 个障碍的路线,对答案的贡献为 \({-1}^k\) 乘以可以对应的棋盘数。
可以发现棋盘数只与路线中钦定的障碍并且该障碍并未明确的个数有关。
并且实际运算中每次遇到障碍转移时乘以 \(-1\) 即可。
于是将未明确的障碍个数,当前行列是否钦定障碍,加入状态,记为 \(f_{x,y,i,0/1,0/1}\)。
转移考虑选不选即可。
实现推荐处理出每个格子是否能被钦定,并用刷表法进行递推。
#include <bits/stdc++.h>
using namespace std;
const int N = 205, mod = 998244353;
int n, p[N][N], f[N][N][N][2][2], fac[N], m;
void sub_(int &x, int y) {
x = x - y < 0 ? x - y + mod : x - y;
}
void add_(int &x, int y) {
x = x + y >= mod ? x + y - mod : x + y;
}
int main() {
scanf("%d", &n), fac[0] = 1;
for (int i = 0; i <= n + 1; i++)
p[i][n + 1] = p[n + 1][i] = p[0][i] = p[i][0] = -1;
for (int i = 1, x; i <= n; i++) {
scanf("%d", &x), fac[i] = 1ll*fac[i - 1]*i%mod;
if (x == -1)
m++;
else {
for (int j = 1; j <= n; j++)
p[j][x] = -1;
for (int j = 1; j <= n; j++)
p[i][j] = -1;
p[i][x] = 1;
}
}
f[0][0][0][0][0] = 1;
for (int i = 0; i <= n + 1; i++)
for (int j = 0; j <= n + 1; j++)
for (int k = 0; k <= n; k++)
for (int r = 0; r < 2; r++)
for (int c = 0, now; c < 2; c++)
if ((now = f[i][j][k][r][c])) {
add_(f[i + 1][j][k][0][c], now);
add_(f[i][j + 1][k][r][0], now);
if (!r && ~p[i][j + 1])
sub_(f[i][j + 1][k + (!p[i][j + 1])][1][1], now);
if (!c && ~p[i + 1][j])
sub_(f[i + 1][j][k + (!p[i + 1][j])][1][1], now);
}
int ans = 0;
for (int i = 0; i <= m; i++)
ans = (ans + 1ll*f[n + 1][n + 1][i][0][0]*fac[m - i])%mod;
printf("%d\n", ans);
}
ARC 118 E - Avoid Permutations
标签:include bit amp c++ ace else 实现 pac clu
原文地址:https://www.cnblogs.com/iqx37f/p/14782899.html