蓝魔法师

蓝魔法师

https://ac.nowcoder.com/acm/problem/20811

做树形dp,dp[i][j]表示根为i的节点,连通块为j时的方案数
在处理的时候有两种情况
断开当前节点和儿子节点,那么直接将儿子节点的所有方案乘上当前节点的方案就行了
如果不断开,那就需要合并,假设当前节点有p个连通块,儿子节点有q个
那么dp[u][p+q]+=dp[u][p]*dp[v][q]

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
#include <stack>
#include <queue>
#include <cmath>
#define ll long long
#define pi 3.1415927
#define inf 0x3f3f3f3f
#define mod 998244353
using namespace std;
#define _int __int128_t
inline int read()
{
    int x=0,f=1;
    char c=getchar();
    while(c<'0'||c>'9') {if(c=='-') f=-1;c=getchar();}
    while(c>='0'&&c<='9') x=(x<<1)+(x<<3)+c-'0',c=getchar();
    return f*x;
}
void print(int x)
{
    if(x < 0) {putchar('-');x = -x;}
    if(x/10) print(x/10);
    putchar(x%10+'0');
}
ll n,m,k,head[3000],tot,vis[3000],dp[3000][3000],sz[3000],tep[3000];
struct node{
    ll to,next;
}edge[6000];
void add(int u,int v)
{
    edge[++tot].to=v;
    edge[tot].next=head[u];
    head[u]=tot;
}
void dfs(int u, int par)
{
    dp[u][1]=1; sz[u]=1;
    for(int i=head[u]; i ;i=edge[i].next){
        int v=edge[i].to;
        if(v==par)
            continue;
        dfs(v,u);
        memset(tep,0,sizeof(tep));
        for(int p=0;p<=min(sz[u],k);p++){
            for(int q=0;q+p<=k && q<=sz[v];q++)
                tep[p+q]=(tep[p+q]%mod+dp[u][p]*dp[v][q]%mod)%mod;
        }
        for(int j=1;j<=k;j++)
            dp[u][j]=tep[j];
        sz[u]+=sz[v];
    }
    for(int i=1;i<=k;i++)
        dp[u][0]=(dp[u][0]+dp[u][i])%mod;
}
int main ()
{
    int T,i,t,j,p,sum=0;
    cin>>n>>k;
    for(i=1;i<n;++i){
        int u=read(),v=read();
        add(u,v);
        add(v,u);
    }
    dfs(1,0);
    cout<<dp[1][0]<<endl;
    return 0;
}
全部评论

相关推荐

10-07 20:48
门头沟学院 Java
听说改名就会有offer:可能是实习上着班想到后面还要回学校给导师做牛马,看着身边都是21-25的年纪,突然emo了了
点赞 评论 收藏
分享
努力学习的小绵羊:我反倒觉得这种挺好的,给不到我想要的就别浪费大家时间了
点赞 评论 收藏
分享
点赞 收藏 评论
分享
牛客网
牛客企业服务