THUWC2018 随机算法

Posted hfccccccccccccc

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了THUWC2018 随机算法相关的知识,希望对你有一定的参考价值。

https://loj.ac/problem/2540

看了题解

题目大意

解法一

独立集那一套东西不是很好处理。为了消除加入一个点对之后点的影响,不妨在向独立集加入一个点时直接顺带加入和它相邻的点,用排列数预计算方案。

解法二

考虑一个集合的最后一个被加入独立集的点是什么。

实现

解法一:

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;

const int MD = 998244353;
int pow_mod(int x, int n) {
    int r = 1;
    while (n) {
        if (n & 1) r = ll(r) * x % MD;
        x = ll(x) * x % MD;
        n >>= 1;
    }
    return r;
}

const int NN = 20;
int g[NN];
int dp[1<<NN], b[1<<NN];
int fac[NN+1], ifac[NN+1], pop[1<<NN];
int n, m;

void precompute() {
    fac[0] = ifac[0] = 1;
    for (int i = 1; i <= NN; i++) {
        fac[i] = ll(i) * fac[i-1] % MD;
        ifac[i] = pow_mod(fac[i], MD - 2);
    }
    for (int i = 1; i < (1 << NN); i++) {
        pop[i] = pop[i>>1] + (i & 1);
    }
}

int perm(int n, int m) {
    if (n < 0 || m < 0 || n < m) return 0;
    return ll(fac[n]) * ifac[n-m] % MD;
}

int main() {
    cin.tie(0);
    ios::sync_with_stdio(false);

    cin >> n >> m;
    precompute();

    for (int i = 0; i < n; i++) g[i] = 1 << i;
    for (int i = 0; i < m; i++) {
        int a, b;
        cin >> a >> b; a--; b--;
        g[a] |= 1 << b;
        g[b] |= 1 << a;
    }

    dp[0] = 1;
    const int S = (1 << n) - 1;
    for (int t = 0; t <= S; t++) {
        if (!dp[t]) continue;
        for (int i = 0; i < n; i++) if (!(t & (1 << i))) {
            int u = t | g[i];
            if (b[t] + 1 > b[u]) {
                b[u] = b[t] + 1;
                dp[u] = 0;
            }
            if (b[t] + 1 == b[u]) {
                dp[u] += ll(dp[t]) * perm(n-1-pop[t], pop[(t&g[i])^g[i]]-1) % MD;
                if (dp[u] >= MD) dp[u] -= MD; 
            }
        }
    }
    cout << ll(dp[S]) * ifac[n] % MD << ‘
‘;
    return 0;
}

解法二:

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;

const int NN = 20;
const int MD = 998244353;
int n, m;
int g[NN];
int inv[NN+1];
int dp[1<<NN], ma[1<<NN];

int main() {
    cin.tie(0);
    ios::sync_with_stdio(false);
    cin >> n >> m;
    inv[1] = 1;
    for (int i = 2; i <= n; i++) {
        inv[i] = ll(MD - MD / i) * inv[MD % i] % MD;
    }
    for (int i = 0; i < n; i++) g[i] = 1 << i;
    for (int i = 0; i < m; i++) {
        int a, b;
        cin >> a >> b; a--; b--;
        g[a] |= 1 << b;
        g[b] |= 1 << a;
    }
    for (int i = 0; i < n; i++) g[i] = ~g[i];
    dp[0] = 1;
    for (int v = 1; v < (1 << n); v++) {
        int pop = 0;
        for (int i = 0; i < n; i++) if ((v >> i) & 1) {
            int u = (v & g[i]);
            if (ma[u] + 1 > ma[v]) {
                ma[v] = ma[u] + 1;
                dp[v] = 0;
            }
            if (ma[u] + 1 == ma[v]) {
                dp[v] += dp[u];
                if (dp[v] >= MD) dp[v] -= MD;
            }
            pop++;
        }
        dp[v] = ll(dp[v]) * inv[pop] % MD;
    }
    cout << dp[(1<<n)-1] << endl;
    return 0;
}

以上是关于THUWC2018 随机算法的主要内容,如果未能解决你的问题,请参考以下文章

[THUWC2017]随机二分图

[THUWC2017]随机二分图

P4547 [THUWC2017]随机二分图(状压,期望DP)

[BZOJ5006][LOJ#2290][THUWC2017]随机二分图(概率+状压DP)

THUWC2018滚粗记

THUWC2018 题解