WC2019 模擬 仙人掌毒題

被期望和仙人掌嚇到了...

Description

給你一堆仙人掌. 每次會有這樣一個詢問: 如果對當前的圖做\(T\)次染色, 每次選一個點, 不管黑白都刷成黑色. 問最後, 白色點互相連接(如果有邊的話), 黑色點同理, 問連通塊個數的期望.

Solution

不會做(恐懼)....就去看題解了.

首先要明白, 在仙人掌裏, 聯通塊數 = 點 - 邊 + 環. 這事對於樹來說, 環上的一條邊被多算了一次, 所以補回來就好.

然後我們就分別計算一種顏色的點期望, 邊期望, 環期望, 把兩種顏色的加起來就好了.

一個點是白點(沒有被染色)的概率\(P_w\)是: \((\frac{n-1}{n})^t\). 所以期望是: \(nP_w\).

相應的, 黑點\(P_b\)就是\(1 - P_w\).

然後是邊. 一條邊兩端都是白點的概率是\((\frac{n-2}{n})^t\). "黑邊"的概率就有點麻煩了, 是1 - 至少有一個點是白點的概率, 爲: \(1 - 2 \times P_w + P_{we}\).

最後是環. 白環也很好算, \((\frac{n - m}{n})^t\)就好了. 黑環不好算, 但我們可以容斥原理.

也就是\(\begin{align}\sum_{j=0}^{m}{(-1)^j {m \choose j} (\frac{n-j}{n})^t}\end{align}\).

只要每次插入邊的時候修改一下期望就可以了.

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <cctype>
#include <vector>
#include <queue>
#include <stack>
#include <cmath>
#include <set>
#include <map>

using namespace std;

typedef long long ll;
typedef unsigned long long ull;
typedef unsigned int uint;
typedef pair<int, int> pii;

inline int rd() {
  register int x = 0, f = 0, c = getchar();
  while (!isdigit(c)) {
    if (c == '-') f = 1;
    c = getchar();
  }
  while (isdigit(c)) x = x * 10 + (c ^ 48), c = getchar();
  return f ? -x : x;
}

const ll mod = 998244353;
const int maxn = 300005;

int n, m, t, w;
int f[maxn], ch[maxn][2], s[maxn], v[maxn]; 
int FA[maxn];
bool tag[maxn], rev[maxn], vis[maxn];
int tot;
ll inv[maxn], fac[maxn], facinv[maxn];

inline ll quick_power(ll base, ll index) {
  ll ret = 1;
  while (index) {
    if (index & 1) ret = ret * base % mod;
    base = base * base % mod;
    index >>= 1;
  }
  return ret;
}
int find(int x) {
  return FA[x] == x ? FA[x] : FA[x] = find(FA[x]);
}
void init() {
  fac[0] = facinv[0] = 1;
  inv[1] = fac[1] = facinv[1] = 1;
  for (int i = 2; i <= n; ++i) {
    fac[i] = fac[i - 1] * i % mod;
    inv[i] = (mod - mod / i) * inv[mod % i] % mod;
    facinv[i] = facinv[i - 1] * inv[i] % mod;
  }
}
inline ll C(int N, int M) {
  return fac[N] * facinv[M] % mod * facinv[N - M] % mod;
}

#define lson ch[x][0]
#define rson ch[x][1]
inline int isroot(int x) {
  return ch[f[x]][0] != x && ch[f[x]][1] != x;
}
inline int getid(int x) {
  return ch[f[x]][1] == x;
}
inline void pushup(int x) {
  s[x] = s[lson] + s[rson] + v[x];
  vis[x] = vis[lson] | vis[rson] | tag[x];
}
inline void pushdown(int x) {
  if (rev[x]) {
    swap(lson, rson);
    rev[lson] ^= 1;
    rev[rson] ^= 1;
    rev[x] = 0;
  }
}
inline void rotate(int x) {
  int y = f[x], z = f[y], k = getid(x);
  if (!isroot(y))
    ch[z][ch[z][1] == y] = x;
  ch[y][k] = ch[x][k ^ 1];
  ch[x][k ^ 1] = y;
  f[ch[y][k]] = y; f[y] = x; f[x] = z;
  pushup(y);
  pushup(x);
}
void pushpath(int x) {
  if (!isroot(x)) pushpath(f[x]);
  pushdown(x);
}
void splay(int x) {
  pushpath(x);
  for (int fa = 0; !isroot(x); rotate(x)) {
    if (!isroot(fa = f[x]))
      rotate(getid(fa) == getid(x) ? fa : x);
    pushup(x);
  }
}
inline void access(int x) {
  for (int y = 0; x; y = x, x = f[x])
    splay(x), ch[x][1] = y, pushup(x);
}
inline void makeroot(int x) {
  access(x); splay(x); rev[x] ^= 1;
}
inline void link(int x, int y) {
  makeroot(x); f[x] = y;
}
inline void split(int x, int y) {
  makeroot(x); access(y); splay(y); 
}
void dfs(int x) {
  if (lson) dfs(lson);
  if (rson) dfs(rson);
  if (x > n) tag[x] = 1;
  pushup(x);
}
#undef lson
#undef rson

int main() {
  freopen("cactus.in", "r", stdin);
  freopen("cactus.out", "w", stdout);
  n = rd(); m = rd(); t = rd(); w = rd();
  init();
  //printf("%lld %lld\n", n * inv[n] % mod, C(100, 0));
  ll BASIC_WHITE_PROB = quick_power(inv[n] * (n - 1) % mod, t);
  ll BASIC_WHITE_EDGE = quick_power(inv[n] * (n - 2) % mod, t);
  ll BASIC_BLACK_EDGE = ((mod + 1 - 2ll * BASIC_WHITE_PROB % mod) % mod
                         + BASIC_WHITE_EDGE) % mod;
  ll E = 1ll * n * BASIC_WHITE_PROB % mod;
  if (w) E = (E + 1ll * n * (1 + mod - BASIC_WHITE_PROB) % mod) % mod;
  for (int i = 1; i <= n; ++i) {
    FA[i] = i;
  }

  int frm, to; 
  tot = n;
  while (m--) {
    frm = rd(); to = rd();
    int fx = find(frm), fy = find(to);
    //printf("%d %d\n", fx, fy);
    if (fx != fy) {
      //puts("new");
      FA[fx] = fy;
      v[++tot] = 1;
      link(frm, tot);
      link(tot, to);
      E = (E - BASIC_WHITE_EDGE + mod) % mod;
      if (w) E = (E - BASIC_BLACK_EDGE + mod) % mod;
      printf("%lld\n", E);
    } else {
      split(frm, to);
      if (vis[to]) printf("%lld\n", E);
      else {
        E = (E - BASIC_WHITE_EDGE + mod) % mod;
        if (w) E = (E - BASIC_BLACK_EDGE + mod) % mod;
        //printf("%lld\n", E);
        dfs(to);
        int M = s[to] + 1;
        //printf("%d\n", M);
        E = (E + quick_power((n - M) * inv[n] % mod, t)) % mod;
        //printf("%lld\n", E);
        if (w) {
          //ll tmp = 0;
          for (int i = 0; i <= M; ++i) {
            ll ret = C(M, i) * quick_power((n - i) * inv[n] % mod, t) % mod;
            //printf("%lld\n", ret);
            if (i & 1) ret = mod - ret;
            //else tmp = (tmp + ret) % mod;
            E = (E + ret) % mod;
            //printf("-%lld\n", E);
          }
          //E = (E + tmp) % mod;
        }
        printf("%lld\n", E);
      }
    }
  } 
  fclose(stdin);
  fclose(stdout);
  return 0;
}

猜你喜欢

转载自www.cnblogs.com/nishikino-curtis/p/10292292.html
今日推荐