有一棵二叉树,初态下没有结点。第一天会长出一个根结点,每个结点都有两个分叉,后面每天都会选择一个还没挂结点的分叉长出一个结点,并标上这天的时间戳。一棵树的权值为它的所有节点两两距离和。经过 \(n\) 天,有可能会生成 \(n!\) 棵不同的树,求这些树的权值和。\(n \leq 2000\)
[HAOI2018] 苹果树 - 组合计数

Solution

考虑当前已经放置了 \(i\) 个点

按边统计,先枚举深子树为 \(j\) 大小的边,然后统计它出现了多少次,每次对答案贡献为 \(2j(n-j)\)

\(i\) 个点无限制,有 \(i!\) 种造法

大小为 \(j\) 的深子树需要从剩下的 \(n-i\) 个点中选出 \(j\) 个点造树,有 \(C_{n-i}^j j!\) 种造法

剩下的点不能放在上述深子树中,所以第一个点有 \(i\) 种放法,第二个点有 \(i+1\) 种放法

于是答案为

\[\sum_{i=1}^n \sum_{j=1}^{n-i} 2j(n-j) i! C_{n-i}^j j!\frac{(n-j-1)!}{(i-1)!}=\sum_{i=1}^n\sum_{j=1}^{n-i} 2ij(n-j)C_{n-i}^j j!(n-j-1)! \]

#include <bits/stdc++.h>
using namespace std;

#define int long long
const int N = 2005;

int n,mod,c[N][N],f[N],ans;

signed main() {
    cin>>n>>mod;
    f[0]=1;
    for(int i=1;i<=n;i++) f[i]=f[i-1]*i%mod;
    for(int i=0;i<=n;i++) {
        c[i][0]=1;
        for(int j=1;j<=i;j++) {
            c[i][j]=(c[i-1][j]+c[i-1][j-1])%mod;
        }
    }
    for(int i=1;i<=n;i++) {
        for(int j=1;j<=n-i;j++) {
            ans+=2*i*j%mod*(n-j)%mod*c[n-i][j]%mod
                *f[j]%mod*f[n-j-1]%mod;
            ans%=mod;
        }
    }
    cout<<ans;
}

相关文章:

  • 2021-05-29
  • 2021-09-26
  • 2021-08-11
  • 2022-01-14
  • 2021-05-31
  • 2021-08-24
猜你喜欢
  • 2021-11-13
  • 2021-12-25
  • 2022-02-28
  • 2021-11-17
  • 2021-06-01
  • 2021-09-25
  • 2021-11-16
相关资源
相似解决方案