[HAOI2018]苹果树

首先发现一次生长相当于去掉一个分支并增加两个分支, 那么所有树出现的概率都是相同的, 一共有 N! 种树。

所以要求输出的那个东西就是不便度的平均数 * 树的总数, 即所有树的不便度之和。

对于某棵树的不便度, 把它拆到边上, 具体地, 这棵树的不便度等于 \(\sum_u siz(u) * (n - siz(u))\)

设 cntu,s 表示点 u 的 siz 为 s 的方案数。(1≤s≤n-u+1)

首先, 生成 1~u, \(\color{red}{u!}\)

其次, 决定 u 子树中的点的标号,\(\color{red}{\dbinom {n-u}{s-1}}\), 然后生成以 u 为根的子树, \(\color{red}{s!}\)

然后生成整棵树的其余部分,\(\color{red}{(u-1)(u-1+1)\cdots(u-1+(n-u-s+1)-1)} = \dfrac{(n-s-1)!}{(u-2)!}\)

所以答案就是:

\[\sum_{u=1}^n\sum_{s=1}^{n-u+1} s(n-s)u!\binom{n-u}{s-1}s!\frac{(n-s-1)!}{(u-2)!} \]

这道题的模数不保证是质数, 组合数可以预处理,只需要化掉除法:

\[\begin{align} &s(n-s)u!\binom{n-u}{s-1}s!\frac{(n-s-1)!}{(u-2)!}\&= s\binom{n-u}{s-1}s!(n-s)!(u-1)u \end{align} \]

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

const int N = 2e3 + 3;

int n, mo;
LL C[N][N], fac[N];

int main() {
	scanf("%d%d", &n, &mo);
	fac[0] = 1ll, C[0][0] = 1ll;
	for(int i = 1; i <= n; ++i) fac[i] = fac[i-1] * (LL)i % mo;
	for(int i = 1; i <= n; ++i) {
		C[i][0] = 1ll;
		for(int j = 1; j <= n; ++j) C[i][j] = (C[i-1][j] + C[i-1][j-1]) % mo;
	}
	LL ans = 0ll;
	for(int u = 1; u <= n; ++u) {
		for(int s = 1; s <= n-u+1; ++s) {
			ans += (LL)s * C[n-u][s-1] % mo * fac[s] % mo * fac[n-s] % mo * (LL)u % mo * (LL)(u-1) % mo;
			ans %= mo;
		}
	}
	cout << (ans%mo + mo) % mo;
	return 0;
}

[HAOI2018]苹果树

上一篇:B. Appleman and Tree 树形DP


下一篇:Android Studio 之创建自定义控件