牛客网 【每日一题】8月5日题目精讲—蓝魔法师
生活随笔
收集整理的這篇文章主要介紹了
牛客网 【每日一题】8月5日题目精讲—蓝魔法师
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
來源:牛客網:
文章目錄
- 題目描述
- 題解:
- 代碼:
題目描述
“你,你認錯人了。我真的,真的不是食人魔。”–藍魔法師
給出一棵樹,求有多少種刪邊方案,使得刪后的圖每個連通塊大小小于等于k,兩種方案不同當且僅當存在一條邊在一個方案中被刪除,而在另一個方案中未被刪除,答案對998244353取模
輸入描述:
第一行兩個整數n,k, 表示點數和限制
2 <= n <= 2000, 1 <= k <= 2000
接下來n-1行,每行包括兩個整數u,v,表示u,v兩點之間有一條無向邊
保證初始圖聯通且合法
輸出描述:
共一行,一個整數表示方案數對998244353取模的結果
示例1
輸入
復制
輸出
復制
題解:
以一號點為根,樹型dp求解
dp[u][x]表示u點連通塊大小為x的方案數
考慮u的兒子v有兩種選擇:
斷開u–v這條邊,v的子樹再怎么分對當前的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];//每個節點的子節點個數 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; }總結
以上是生活随笔為你收集整理的牛客网 【每日一题】8月5日题目精讲—蓝魔法师的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 点云综述学习笔记(一)
- 下一篇: 资本主义是什么意思 什么是资本主义