被期望和仙人掌嚇到了...
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;
}