時間限制:c/c++ 1秒,其他語言2秒
空間限制:c/c++ 262144k,其他語言524288k
64bit io format: %lld
「你,你認錯人了。我真的,真的不是食人魔。」--藍魔法師
給出一棵樹,求有多少種刪邊方案,使得刪後的圖每個連通塊大小小於等於k,兩種方案不同當且僅當存在一條邊在乙個方案中被刪除,而在另乙個方案中未被刪除,答案對998244353取模
第一行兩個整數n,k, 表示點數和限制2 <= n <= 2000, 1 <= k <= 2000
接下來n-1行,每行包括兩個整數u,v,表示u,v兩點之間有一條無向邊
保證初始圖聯通且合法
共一行,乙個整數表示方案數對998244353取模的結果示例1
複製
5 2複製1 21 3
2 42 5
7不會樹形dp,思路參考於
用dp【u】【p】表示根節點為u的連通塊(包括u),它的連通塊大小為p時的方案數
其中dp【u】表示所有方案之和
這樣就是乙個計數問題,而計數問題最怕遺漏和重複,狀態該如何轉移呢?
對於它的乙個子節點v,當u訪問到v時,假設之前已經訪問了幾個子節點,之前訪問的節點個數為siz[u],那麼假設我們要讓連通塊大小為p,p可以從兩個地方來:從之前訪問過的節點中,也就是siz【u】,也可以從現在正在訪問的節點v,也就是siz【v】。那麼根據乘法計數原理,答案就是兩者相乘。
搜尋**如下:
for(int i=0;i所以整個**也就很好寫了。
#include #include #include #include #include #include using namespace std;
typedef long long ll;
const ll mod=998244353;
const int maxn=2000+10;
vectorg[maxn];
ll dp[maxn][maxn];
ll n,k;
ll siz[maxn];//每個節點的子節點個數
void dfs(int u)
} for(int j=1;j<=k;j++)
siz[u]+=siz[v];
} for(int i=1;i<=k;i++)
}int main()
memset(dp,0,sizeof(dp));
dfs(1);
printf("%lld\n",dp[1][0]);
}return 0;
}
樹形dp 組合數學 藍魔法師
dp i j 表示對於i這個子樹來說,i所在的連通塊大小為j,並且整棵樹合法的方案數。接下來就是類似揹包的解法了。遍歷每個兒子的分支,每個分支要麼刪除,要麼不刪除。1.刪除 刪除此邊,那麼就意味著當前以u節點連通塊大小為k的方案數 都可以 乘 v節點連通塊大小所有的方案數 2.不刪除 不刪除就相當於...
Wannafly27 C 藍魔法師 樹形DP
wannafly27 c 藍魔法師 給定一棵樹,刪除一些邊,使每個連通塊不超過k個節點 includeusing namespace std const int max 2e3 5 const int mod 998244353 int n,k struct p e max 1 int head m...
藍魔法師 牛客
將一顆 n 1 leq n leq 2000 個結點的樹,分成 t 1 leq t leq n 個連通塊,且每個連通塊的大小都小於或者等於 k 1 leq k leq 2000 求劃分方案數?dp i j 以 i 為根的子樹向父親結點 u 提供 j 個點的貢獻 dp fa i cnt 1 cnt 2...