PKUSC2018 随机算法

https://loj.ac/problem/2540

题解

\(O(n \cdot 3^n)\) 的 DP 应该很好想,考虑一下怎么优化状态。

\(max_{s}\) 表示集合 \(s\) 取到的最大独立集大小,令 \(dp_{s}\) 表示集合 \(s\) 取到对应的最大独立集的概率 然。

枚举一下 \(s\) 中最后加入独立集的数是哪个,把 \(s\) 中和 \(i\) 有连接的都删掉,然后转移,时间复杂度 \(O(n \cdot 2^{n})\)

#include <bits/stdc++.h>

using namespace std;

const int md = 998244353;
const int N = 20;

void add(int &a, int b) {
  a += b;
  if (a >= md) {
    a -= md;
  }
}

int mul(int a, int b) {
  return (long long) a * b % md;
}

int n, m, g[N], inv[N + 10], f[1 << N], mx[1 << N], l2[1 << N];

int main() {
  scanf("%d %d", &n, &m);
  for (int i = 0; i < n; i++) {
    g[i] = 1 << i;
  }
  for (int i = 0; i < m; i++) {
    int x, y;
    scanf("%d %d", &x, &y);
    x--; y--;
    g[x] |= 1 << y;
    g[y] |= 1 << x;
  }
  inv[1] = 1;
  for (int i = 2; i <= n; i++) {
    inv[i] = mul(md - md / i, inv[md % i]);
  }
  for (int i = 0; i < n; i++) {
    l2[1 << i] = i;
  }
  f[0] = 1;
  mx[0] = 0;
  const int S = (1 << n) - 1;
  for (int v = 1; v <= S; v++) {
    int pop = 0;
    int t = v;
    while (t > 0) {
      int i = l2[t & -t];
      int u = v & (~g[i]);
      if (mx[u] + 1 == mx[v]) {
        add(f[v], f[u]);
      } else if (mx[u] + 1 > mx[v]) {
        mx[v] = mx[u] + 1;
        f[v] = f[u];
      }
      t -= t & -t;
      pop++;
    }
    f[v] = mul(f[v], inv[pop]);
  }
  printf("%d\n", f[S]);
  return 0;
}

猜你喜欢

转载自www.cnblogs.com/hfccccccccccccc/p/10022273.html