首先注意到每种树都是等概率出现的,于是将问题转化成计数求和问题。
f[n]表示所有n个点的树的两两点距离和的总和。
g[n]表示所有n个点的树的所有点到根的距离和的总和。
h[n]表示n个点的树的可能形态数。
转移:
f[n]+={[f[i]+(g[i]+h[i]*i)·(n-i)]·h[n-i-1]+[f[n-i-1]+(g[n-i-1]+h[n-i-1]*(n-i-1))·(i+1)]·h[i]}·C(n-1,i)
g[n]+=[(g[i]+h[i]*i)·h[n-i-1]+(g[n-i-1]+h[n-i-1]*(n-i-1))·h[i]]·C(n-1,i)
h[n]=h[i]·h[n-i-1]·C(n-1,i)
其中i从0到n-1枚举。
1 #include<cstdio> 2 #include<algorithm> 3 #define rep(i,l,r) for (int i=(l); i<=(r); i++) 4 typedef long long ll; 5 using namespace std; 6 7 const int N=2010; 8 int n,mod,C[N][N],f[N],g[N],h[N]; 9 void inc(int &x,int y){ x+=y; if (x>=mod) x-=mod; } 10 11 int main(){ 12 freopen("bzoj5305.in","r",stdin); 13 freopen("bzoj5305.out","w",stdout); 14 scanf("%d%d",&n,&mod); C[0][0]=1; f[0]=g[0]=0; h[0]=1; 15 rep(i,1,n){ C[i][0]=1; rep(j,1,i) C[i][j]=(C[i-1][j-1]+C[i-1][j])%mod; } 16 rep(i,1,n){ 17 rep(j,0,i-1) h[i]=(h[i]+1ll*h[j]*h[i-j-1]%mod*C[i-1][j])%mod; 18 rep(j,0,i-1) g[i]=(g[i]+((g[j]+1ll*j*h[j])%mod*h[i-j-1]+(g[i-j-1]+1ll*(i-j-1)*h[i-j-1])%mod*h[j])%mod*C[i-1][j])%mod; 19 rep(j,0,i-1) f[i]=(f[i]+((f[j]+(g[j]+1ll*j*h[j])%mod*(i-j))%mod*h[i-j-1]+(f[i-j-1]+(g[i-j-1]+1ll*(i-j-1)*h[i-j-1])%mod*(j+1))%mod*h[j])%mod*C[i-1][j])%mod; 20 } 21 printf("%d ",f[n]); 22 return 0; 23 }