[HAOI2018] 苹果树

显然,随机产生的n个节点二叉树共有n!中结构,且出现每种结构的概率相同,因此之需求所有方案的不方便度之和即可。

让边的编号为儿子节点的编号。考虑边i(i∈[2,n])在所有情况下产生的贡献?(很重要的方法

枚举点i的子树大小t(t∈[1,n-i+1]),对应的每张方案边i都有t(n-t)的贡献。

计算点i的子树大小t的方案数?形成边的方案i!, 子树的方案(有t-1个未知编号)t!*C(n-i,t-1),还有n-i+1-t个点依次在有i-1个空分支的基础上生长,这部分的方案为i-1的n-i+1-t上阶乘幂,即(n-t-1)!/(i-2)!

综上所述,答案为sum_{i∈[2,n]} sum_{t∈[1,n-i+1]} i!t(n-t)t!C(n-i,t-1)*(n-t-1)!/(i-1)!,O(n^2)算法跃然键上

似乎有的数不一定有逆?

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

const int N=2e3+10;

int n,P;
int fc[N],c[N][N],d[N][N];

int main() {
	scanf("%d%d",&n,&P);
	fc[0]=c[0][0]=1;
	for(int i=1; i<=n; ++i) {
		for(int j=1; j<=i; ++j) 
			c[i][j]=(c[i-1][j-1]+c[i-1][j])%P;
		c[i][0]=1; fc[i]=1LL*fc[i-1]*i%P;
	}
	for(int i=1; i<n; ++i) {
		d[i][0]=1;
		for(int j=1; j<=n; ++j) 
			d[i][j]=1LL*d[i][j-1]*(i+j-1)%P;
	}
	int ans=0;
	for(int i=2; i<=n; ++i) {
		for(int t=1; t<=n-i+1; ++t) 
			ans=(ans+1LL*fc[i]*t%P*(n-t)%P*fc[t]%P*c[n-i][t-1]%P*d[i-1][n-i+1-t]%P)%P;
	}
	printf("%d\n",ans);
	return 0;
}
posted @ 2019-06-10 14:07  nosta  阅读(115)  评论(0编辑  收藏  举报