[BZOJ5305][HAOI2018]苹果树(DP)

首先注意到每种树都是等概率出现的,于是将问题转化成计数求和问题。

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\n",f[n]);
22     return 0;
23 }

 

posted @ 2019-01-16 17:40  HocRiser  阅读(185)  评论(2编辑  收藏  举报