蓝魔法师

蓝魔法师

 

 

 

 

 分析:sz保存包括自身的所有子孙总节点数(为了求连通块的大小做准备)

dp[i][j]表示只考虑根为i的子树,包含节点i的联通块大小为j的方案个数

dp[i][0]表示dp[i][1]+...+dp[i][k]

一棵子树根节点为u的连通块(包括u)对于它的一个子节点v,当u访问到v时,假设之前已经访问了几个子节点,

之前访问的节点个数为sz[u],那么假设我们要让连通块大小为p,p可以从两个地方来:

从之前访问过的节点中,也就是sz【u】,也可以从现在正在访问的节点v,也就是sz【v】

u提供连通分量的j个 v(u的子节点,与u相连)提供k个,连起来该连通分量大小就是k+j

乘法原理方案总个数为dp[u][j]*dp[v][k];

总结:dpi,u+v=∑(dpi,u∗dpson,v)

   dpi,0=fi,j(j<=k)

   dpi,j=0,j>K

AC_Code

 

 1 #include <iostream>
 2 #include <bits/stdc++.h>
 3 using namespace std;
 4 typedef long long ll;
 5 const int maxn = 2e3+10;
 6 const int inf=0x3f3f3f3f;
 7 const int mod=998244353;
 8 #define rep(i,first,last) for(int i=first;i<=last;i++)
 9 #define dep(i,first,last) for(int i=first;i>=last;i--)
10 struct edge{ll to,nxt;}e[maxn<<1];
11 ll dp[maxn][maxn],sz[maxn],tmp[maxn];
12 ll n,m,u,v,cnt,head[maxn<<1];
13 void addedge(ll u,ll v){
14     e[cnt].to=v;
15     e[cnt].nxt=head[u];
16     head[u]=cnt++;
17 }
18 void add(ll &x,ll y){ x=(x+y>=mod?x+y-mod:x+y);}
19 void dfs(ll u,ll fa){
20     sz[u]=1;
21     dp[u][1]=1;
22     for(ll i=head[u];~i;i=e[i].nxt){
23         ll v=e[i].to;
24         if( v!=fa ){
25             dfs(v,u);
26             rep(j,1,sz[u]+sz[v]) tmp[j]=0;//初始化
27             rep(j,0,sz[u]){
28                 rep(k,0,sz[v]){
29                     add(tmp[j+k],1ll*dp[v][k]*dp[u][j]%mod);
30                 }
31             }
32             sz[u]+=sz[v];
33             rep(j,1,sz[u]) dp[u][j]=tmp[j];
34         }
35     }
36     dp[u][0]=0;
37     rep(j,1,m) add(dp[u][0],dp[u][j]);
38     rep(j,m+1,sz[u]) dp[u][j]=0;
39 }
40 int main()
41 {
42     memset(head,-1,sizeof(head));
43     scanf("%lld%lld",&n,&m);
44     rep(i,1,n-1){
45         ll u,v;
46         scanf("%lld%lld",&u,&v);
47         addedge(u,v);
48         addedge(v,u);
49     }
50     dfs(1,0);
51     printf("%lld\n",dp[1][0]);
52     return 0;
53 }

 

posted @ 2020-02-24 18:28  swsyya  阅读(216)  评论(0编辑  收藏  举报

回到顶部