1. 程式人生 > 其它 >[題解][P5206][WC2019] 數樹 (op = 1)

[題解][P5206][WC2019] 數樹 (op = 1)

簡要題意

給定 \(n, y\)

一張圖有 \(|V| = n\) 個點,現在給出兩棵樹 \(T_1=G(V, E_1)\)\(T_2=G(V, E_2)\)

定義這兩棵樹的權值 \(F(E_1, E_2)\)\(y\)\(G'=(V,E_1\cap E_2)\) 的聯通塊個數次方。

\(F(E_1, E_2) = y^{n - |E_1\cap E_2|}\),給定 \(E_1\),計算 \(\sum_{E_2} F(E_1, E_2)\)

其中 \(n\le 10^5\)。答案對 \(998244353\) 取模。

解題思路

首先我們要找到一個合適的形式來表示我們的答案,部分列舉 \(S=E_1\cap E_2\)

,則答案為:

\[\sum_{E_2} \sum_{S=E_1\cap E_2} y^{n-|S|} \]

其中 \(S=E_1\cap E_2\) 這個恰好的條件限制較強,考慮容斥將限制弱化為 \(S\subseteq E_1\cap E_2\).

不妨考慮這樣一個容斥原理的式子:

\[f(S)=\sum_{T\subseteq S}\sum_{P\subseteq T}(-1)^{|T|-|P|}f(P) \]

代入到原來的式子中,得到:

\[\begin{aligned} &\sum_{E_2} \sum_{S=E_1\cap E_2} y^{n-|S|}\\ =&\sum_{E_2} \sum_{T\subseteq E_1\cap E_2} \sum_{P\subseteq T}(-1)^{|T|-|P|}y^{n-|P|}\\ =&\sum_{T\subseteq E_1}g(T)\sum_{P\subseteq T}(-1)^{|T|-|P|}y^{n-|P|}\\=&\sum_{T\subseteq E_1}g(T)y^{n-|T|}\sum_{P\subseteq T}(-y)^{|T|-|P|}\\ =&\sum_{T\subseteq E_1}g(T)\sum_{P\subseteq T}(-1)^{|T|-|P|}y^{n-|P|}\\=&\sum_{T\subseteq E_1}g(T)y^{n-|T|}\sum_{|P|=0}^{|T|}\binom{|T|}{|P|}(-y)^{|T|-|P|}\\ =&\sum_{T\subseteq E_1}g(T)\sum_{P\subseteq T}(-1)^{|T|-|P|}y^{n-|P|}\\=&\sum_{T\subseteq E_1}g(T)y^{n-|T|}(1-y)^{|T|}\\ \end{aligned} \]

其中 \(g(T)\)

表示包含邊集 \(T\)\(E_2\) 的個數。

假設 \(G=(V,T)\) 為一個由 \(k\) 個大小分別為 \(a_i\) 的連通塊組成的森林,則:

\[g(T)=n^{k-2}\prod_{i=1}^ka_i \]

繼續代入 (注意到 \(n=|T|+k\) ),得:

\[\begin{aligned} &\sum_{T\subseteq E_1}g(T)y^{n-|T|}(1-y)^{|T|}\\ =&\sum_{T\subseteq E_1}n^{k-2}\prod_{i=1}^ka_i\ y^k(1-y)^{n-k}\\ =&\frac{(1-y)^n}{n^2}\sum_{T\subseteq E_1}\prod_{i=1}^k\frac{ny}{1-y}\ a_i \end{aligned} \]

即一個大小為 \(a\)

的連通塊為答案貢獻一個乘積 Ka,其中 \(K = \frac{ny}{1-y}\)

據此可以容易得到一個 \(O(n^2)\) 的 DP,\(f(x,i)\) 表示 \(x\) 的子樹中,\(x\) 所在的連通塊大小為 \(i\) 的答案。

考慮到這個貢獻可以拆分表示為 \(\prod_{i=1}^k(K+K+K+\cdots K)\),故合併兩個大小分別為 \(x,y\) 的連通塊時,新的貢獻其實就是 \(K(x+y)\prod_{i\ne now}Ka_i\).

這樣狀態可以優化為 \(f(x,0/1)\) 表示 \(x\) 的子樹中,當前連通塊是否已經做出貢獻。

那麼轉移就是 (前面是選邊 \((x,y)\),後面是不選):

\[\begin{aligned} &f(x,1)=f(x,1)f(y,1)\ +\ f(x,1)f(y,0)+f(x,0)f(y,1)\\ &f(x,0)=f(x,0)f(y,1)\ +\ f(x,0)f(y,0) \end{aligned} \]

程式碼

void dfs(int x, int fx){
	siz[x] = 1, f[x] = coef, g[x] = 1;
	for(int i = head[x]; i; i = e[i].nx){
		int y = e[i].to; if(y == fx) continue;
		dfs(y, x);
		int sum = Mod((LL) f[x] * g[y] % mod + (LL) g[x] * f[y] % mod - mod);
		MOD(f[x] = (LL) f[x] * f[y] % mod + sum - mod);
		MOD(g[x] = (LL) g[x] * f[y] % mod + (LL) g[x] * g[y] % mod - mod);
	}
}

void solve(){
    coef = (LL) n * y % mod * qpow(1 - y + mod) % mod;
    dfs(1, 0);
    cout << (LL) f[1] * qpow(1 - y + mod, n) % mod * qpow((LL) n * n % mod) % mod << endl;
}