# LOJ2540. 「PKUWC2018」随机算法【概率期望DP+状压DP】

## 思路

#include<bits/stdc++.h>

using namespace std;

const int Mod = 998244353;
const int N = 21;

int n, m, w[N];
int fac[N], inv[N], cnt[1 << N];
int dp[N][1 << N];

int main() {
#ifdef dream_maker
freopen("input.txt", "r", stdin);
#endif
function<int(int a, int b)> add = [&](int a, int b) {
return (a += b) >= Mod ? a - Mod : a;
};

function<int(int a, int b)> sub = [&](int a, int b) {
return (a -= b) < 0 ? a + Mod : a;
};

function<int(int a, int b)> mul = [&](int a, int b) {
return (long long) a * b % Mod;
};

function<int(int a, int b)> fast_pow = [&](int a, int b) {
int res = 1;
for (; b; b >>= 1, a = mul(a, a))
if (b & 1) res = mul(res, a);
return res;
};

function<int(int a, int b)> P = [&](int a, int b) {
return (a < b) ? 0 : mul(fac[a], inv[a - b]);
};

scanf("%d %d", &n, &m);
int up = (1 << n) - 1;
for (int i = 1; i <= n; i++) w[i] = 1 << (i - 1);
for (int i = 1; i <= m; i++) {
int u, v; scanf("%d %d", &u, &v);
w[u] |= 1 << (v - 1);
w[v] |= 1 << (u - 1);
}
inv[0] = fac[0] = 1;
for (int i = 1; i <= n; i++) fac[i] = mul(fac[i - 1], i);
inv[n] = fast_pow(fac[n], Mod - 2);
for (int i = n - 1; i >= 1; i--) inv[i] = mul(inv[i + 1], i + 1);
for (int i = 1; i <= up; i++) {
for (int j = 1; j <= n; j++) {
cnt[i] += (i >> (j - 1)) & 1;
}
}
dp[0][0] = 1;
for (int i = 1; i <= n; i++) {
for (int s = 0; s <= up; s++) if (dp[i - 1][s]) {
for (int j = 1; j <= n; j++) if (!((s >> (j - 1)) & 1)) {
dp[i][s | w[j]] = add(dp[i][s | w[j]], mul(dp[i - 1][s], P(n - cnt[s] - 1, cnt[w[j] ^ (w[j] & s)] - 1)));
}
}
}
for (int i = n; i >= 1; i--) if (dp[i][up]) {
printf("%d", mul(dp[i][up], inv[n]));
break;
}
return 0;
}

posted @ 2018-12-12 18:48  Dream_maker_yk  阅读(169)  评论(0编辑  收藏