牛客网 【每日一题】8月5日题目精讲—蓝魔法师
來源:牛客網(wǎng):
文章目錄
- 題目描述
- 題解:
- 代碼:
題目描述
“你,你認(rèn)錯(cuò)人了。我真的,真的不是食人魔。”–藍(lán)魔法師
給出一棵樹,求有多少種刪邊方案,使得刪后的圖每個(gè)連通塊大小小于等于k,兩種方案不同當(dāng)且僅當(dāng)存在一條邊在一個(gè)方案中被刪除,而在另一個(gè)方案中未被刪除,答案對(duì)998244353取模
輸入描述:
第一行兩個(gè)整數(shù)n,k, 表示點(diǎn)數(shù)和限制
2 <= n <= 2000, 1 <= k <= 2000
接下來n-1行,每行包括兩個(gè)整數(shù)u,v,表示u,v兩點(diǎn)之間有一條無向邊
保證初始圖聯(lián)通且合法
輸出描述:
共一行,一個(gè)整數(shù)表示方案數(shù)對(duì)998244353取模的結(jié)果
示例1
輸入
復(fù)制
輸出
復(fù)制
題解:
以一號(hào)點(diǎn)為根,樹型dp求解
dp[u][x]表示u點(diǎn)連通塊大小為x的方案數(shù)
考慮u的兒子v有兩種選擇:
斷開u–v這條邊,v的子樹再怎么分對(duì)當(dāng)前的x不存在影響了,乘起來即可:dp[u][x]=dp[u][x] * sumv
如果不斷開u–v:u中大小為i的連通塊與v中大小為j的連通塊合成大小為i+j的連通塊
dp[u][i+j]+=dp[u][i] * dp[v][x-i]
代碼:
#include <cstdio> #include <cstring> #include <algorithm> #include <iostream> #include <vector> #include <cmath> using namespace std; typedef long long ll; const ll mod=998244353; const int maxn=2000+10; vector<int>G[maxn]; ll dp[maxn][maxn]; ll n,k; ll temp[maxn]; ll size[maxn];//每個(gè)節(jié)點(diǎn)的子節(jié)點(diǎn)個(gè)數(shù) void dfs(int u){size[u]=1;dp[u][1]=1;for(int i=0;i<G[u].size();i++){int v=G[u][i];dfs(v);memset(temp,0,sizeof(temp));for(int ii=1;ii<=size[u];ii++){for(int j=0;j<=min(k-ii,size[v]);j++){temp[ii+j]=(temp[ii+j]%mod+dp[u][ii]*dp[v][j]%mod)%mod;}}for(int j=1;j<=k;j++){dp[u][j]=temp[j];}size[u]+=size[v];}for(int i=1;i<=k;i++){dp[u][0]+=dp[u][i];dp[u][0]%=mod;} }int main(){while(scanf("%lld%lld",&n,&k)!=EOF){for(int i=1;i<n;i++){int u,v;scanf("%d%d",&u,&v);G[u].push_back(v);}memset(dp,0,sizeof(dp));dfs(1);printf("%lld\n",dp[1][0]);}return 0; }總結(jié)
以上是生活随笔為你收集整理的牛客网 【每日一题】8月5日题目精讲—蓝魔法师的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 点云综述学习笔记(一)
- 下一篇: (牛客网)树型dp