- ……先自闭两个小时
- 好吧,不会写,看了看题解,说一下思路吧。
- 首先第一个小 t r i c k trick trick是,按照题意去建树, n n n个点能组成的二叉树的数量正好是 n ! n! n!。因此求期望的时候我们不需要乘概率了,直接累加答案就好。
- 再来描述一下问题:求所有不同的树上两两节点之间的距离之和。
- 这个问题这样描述,真的很难求,考虑转化思路,求每一条边对答案的贡献。
- 除了根节点每一个点都有一条连向父亲的边,我们就依次求这个边的贡献。先枚举点的编号,再枚举子树的大小。设当前点为
i
i
i,子树大小为
s
i
z
siz
siz,对一个方案的贡献就是
s
i
z
∗
(
n
−
s
i
z
)
siz*(n-siz)
siz∗(n−siz)。但是我们还需要乘上方案数。考虑当前点为
i
i
i,子树大小为
s
i
z
siz
siz的方案数如何求:首先从编号1到编号
i
i
i取的这
i
i
i个点有
i
!
i!
i!种方案。然后从剩下的点里面选出了
s
i
z
−
1
siz-1
siz−1个点放在了
i
i
i这颗子树里,需要乘上一个组合数。这
s
i
z
−
1
siz-1
siz−1个点相当于以i为根任意选位置添加,方案数为
s
i
z
!
siz!
siz!。剩下的
n
−
i
−
s
i
z
+
1
n-i-siz+1
n−i−siz+1个节点,第一个点有
i
−
1
i-1
i−1种选择,第二个有
i
−
1
+
1
i-1+1
i−1+1种,第三个……最后一个有
i
−
1
+
n
−
i
−
s
i
z
i-1+n-i-siz
i−1+n−i−siz即
n
−
s
i
z
−
1
n-siz-1
n−siz−1种选择。这些都乘起来,得到:
a n s = ∑ i = 2 n i ! ∑ s i z = 1 n − i + 1 C n − i s i z − 1 s i z ! ( n − s i z ) s i z ( n − s i z − 1 ) ! ( i − 2 ) ! ans=\sum_{i=2}^ni!\sum_{siz=1}^{n-i+1}C_{n-i}^{siz-1}siz!(n-siz)siz\frac{(n-siz-1)!}{(i-2)!} ans=i=2∑ni!siz=1∑n−i+1Cn−isiz−1siz!(n−siz)siz(i−2)!(n−siz−1)! - 模数
p
p
p不确定,显然除法不合适,我们需要设法把除法变成乘法。阶乘除以阶乘,考虑和组合数之间的转化。
( n − s i z − 1 ) ! ( i − 2 ) ! = C n − s i z − 1 i − 2 ∗ ( n − s i z − i + 1 ) ! \frac{(n-siz-1)!}{(i-2)!}=C_{n-siz-1}^{i-2}*(n-siz-i+1)! (i−2)!(n−siz−1)!=Cn−siz−1i−2∗(n−siz−i+1)!
a n s = ∑ i = 2 n i ! ∑ s i z = 1 n − i + 1 C n − i s i z − 1 s i z ! ( n − s i z ) s i z C n − s i z − 1 i − 2 ∗ ( n − s i z − i + 1 ) ! ans=\sum_{i=2}^ni!\sum_{siz=1}^{n-i+1}C_{n-i}^{siz-1}siz!(n-siz)sizC_{n-siz-1}^{i-2}*(n-siz-i+1)! ans=i=2∑ni!siz=1∑n−i+1Cn−isiz−1siz!(n−siz)sizCn−siz−1i−2∗(n−siz−i+1)! - O ( n 2 ) O(n^2) O(n2)预处理组合数,直接递推即可。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=2010;
int n,p;ll ans,jie[N],c[N][N];
int main(){
scanf("%d%d",&n,&p);
jie[0]=jie[1]=1;
for(int i=2;i<=n;++i) jie[i]=1LL*jie[i-1]*i%p;
c[0][0]=1;
for(int i=1;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])%p;
}
for(int i=2;i<=n;++i){
for(int siz=1;siz<=n-i+1;siz++){
ans=(ans+1LL*jie[i]*c[n-i][siz-1]%p*jie[siz]%p*siz%p*(n-siz)%p*c[n-siz-1][i-2]%p*jie[n-siz-i+1]%p)%p;
}
}
cout<<ans<<endl;
return 0;
}