2021上海ICPC Edge Groups(树形dp,组合数学)

2021上海ICPC Edge Groups(树形dp,组合数学)

题目链接
题意:给一颗树,把所有n-1条边两两分组,每组的两条边要有公共节点,求方案数

思路:首先定义 d p [ u ] dp[u] dp[u] s i z [ u ] siz[u] siz[u],代表以u为根的时候产生的方案数,与以u为根节点的子树会提供多少个贡献,贡献的定义是有多少个子树的节点是偶数个。然后可以观察到,如果对于一个单独的子树,当节点个数为奇数的时候,只能够产生一种组合方式,因为这个时候子树内部的边是偶数,要全部配对的话就只有一种组合方式,只有节点个数是偶数的时候,才会对父节点提供新的组合方式,因为这个时候会有一条边是独立出来的。所以当 s i z [ v ] m o d 2 = = 0 siz[v] mod 2 == 0 siz[v]mod2==0的时候 s i z [ u ] siz[u] siz[u]才会+1,然后根据乘法原理, d p [ u ] ∗ = d p [ v ] dp[u]*=dp[v] dp[u]=dp[v]。最后因为有 s i z [ u ] 的 贡 献 siz[u]的贡献 siz[u],他们可以选择两两组合,剩下得往上组合,所以最后还要遍历 s i z [ u ] siz[u] siz[u],把他累乘到 d p [ u ] dp[u] dp[u]

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N = 1e5+10;
const int MOD = 998244353;
int head[N], idx;
struct Edge{int to, nxt;}e[N << 1];
void add(int u, int v) {e[++idx].to = v, e[idx].nxt = head[u], head[u] = idx;}
int siz[N], dp[N];
void dfs(int u, int fa)
{
    dp[u] = 1;
    for (int i = head[u]; i; i = e[i].nxt) {
        int v = e[i].to;
        if (v == fa) continue;
        dfs(v, u);
        dp[u] *= dp[v]; dp[u] %= MOD;
        if (siz[v] % 2 == 0) siz[u]++;
    }
    for (int i = 1; i <= siz[u]; i += 2) dp[u] = dp[u] * i % MOD; 
}

signed main()
{
    int n;
    cin >> n;
    for (int i = 1; i < n; i++) {
        int u, v;
        cin >> u >> v;
        add(u, v); add(v, u);
    } 
    dfs(1, 0);
    cout << dp[1];
    return 0;
}
  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值