日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

[AtCoder Educational DP Contest] V - Subtree(树形dp + 前缀积/后缀积)

發(fā)布時間:2023/12/3 编程问答 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 [AtCoder Educational DP Contest] V - Subtree(树形dp + 前缀积/后缀积) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

problem

luogu

給一棵樹,對每一個節(jié)點染成黑色或白色。

對于每一個節(jié)點,求強制把這個節(jié)點染成黑色的情況下,所有的黑色節(jié)點組成一個聯(lián)通塊的染色方案數(shù),答案對 MMM 取模。

1≤n≤1e5,2≤M≤1e91\le n\le 1e5,2\le M\le 1e91n1e5,2M1e9

solution

換根 dpdpdp

f(i):f(i):f(i):iii 為根的子樹,iii 為黑色的合法方案數(shù)。(全局是以 111 為根的)

則有:f(u)=∏v∈sonu(f(v)+1)f(u)=\prod_{v\in son_u}(f(v)+1)f(u)=vsonu??(f(v)+1)。加一是整棵子樹全為白色的方案數(shù)。

g(i):g(i):g(i):iii 為根的子樹,iii 為黑色的合法方案數(shù)。(這里的子樹指代的是 iii 的祖先及兄弟,即去掉 iii 原來子樹的剩余部分)

顯然答案為 f(i)?g(i)f(i)*g(i)f(i)?g(i)

考慮如何求出 g(i)g(i)g(i)

對于一對父子關系 f(u)=∏(f(son)+1)f(u)=\prod(f(son)+1)f(u)=(f(son)+1),其中就有兒子提供的一個貢獻 f(v)+1f(v)+1f(v)+1,我們需要去掉。

即,g(v)=g(u)?∏(f(son)+1)f(v)+1g(v)=g(u)*\frac{\prod(f(son)+1)}{f(v)+1}g(v)=g(u)?f(v)+1(f(son)+1)?

但是 MMM 并不是質數(shù),所以不能求逆元。

我們可以對每個 uuu 維護出兒子貢獻 ∏(f(v)+1)\prod(f(v)+1)(f(v)+1) 的前綴積和后綴積。

只要知道某個兒子在其兒子中的編號即可。

具體可見代碼實現(xiàn)。

code

#include <bits/stdc++.h> using namespace std; #define int long long #define maxn 100005 vector < int > pre[maxn], suf[maxn]; vector < int > G[maxn]; int f[maxn], g[maxn]; int n, mod; void dfs1( int u, int fa ) {f[u] = 1;for( int v : G[u] )if( v == fa ) continue;else dfs1( v, u ), f[u] = f[u] * (f[v] + 1) % mod;pre[u].resize( G[u].size() + 1, 1 );suf[u].resize( G[u].size() + 1, 1 );for( int i = 1;i < G[u].size();i ++ ) {pre[u][i] = pre[u][i - 1];if( G[u][i - 1] ^ fa ) pre[u][i] = pre[u][i] * (f[G[u][i - 1]] + 1) % mod;}for( int i = G[u].size() - 2;i >= 0;i -- ) {suf[u][i] = suf[u][i + 1];if( G[u][i + 1] ^ fa )suf[u][i] = suf[u][i] * (f[G[u][i + 1]] + 1) % mod;} } void dfs2( int u, int fa ) {for( int i = 0;i < G[u].size();i ++ ) {int v = G[u][i];if( v == fa ) continue;g[v] = pre[u][i] * suf[u][i] % mod * g[u] % mod + 1;//加1是父親代表的子樹全為白 dfs2( v, u );} } signed main() {scanf( "%lld %lld", &n, &mod );for( int i = 1, u, v;i < n;i ++ ) {scanf( "%lld %lld", &u, &v );G[u].push_back( v );G[v].push_back( u );}dfs1( 1, 0 );g[1] = 1;dfs2( 1, 0 );for( int i = 1;i <= n;i ++ ) printf( "%lld\n", g[i] * f[i] % mod );return 0; }

總結

以上是生活随笔為你收集整理的[AtCoder Educational DP Contest] V - Subtree(树形dp + 前缀积/后缀积)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內容還不錯,歡迎將生活随笔推薦給好友。