P4492-[HAOI2018]蘋果樹【dp】

Quant-Ask發表於2020-12-11

正題

題目連結:https://www.luogu.com.cn/problem/P4492


題目大意

開始有一個節點,第 i i i次在一個兒子不超過 2 2 2的節點下面長出一個新兒子編號為 i i i。求所有方案下樹的路徑長度和。


解題思路

考慮計算每條邊的貢獻,設 g i g_i gi表示大小為 i i i的樹的形態個數, f i f_i fi表示所有大小為 i i i的樹的路徑長度和。然後題目給出的要求就是子節點編號比父節點大。

那麼 g g g有轉移 g i + 1 = ∑ j = 0 i g j g i − j C i j g_{i+1}=\sum_{j=0}^ig_jg_{i-j}C_{i}^j gi+1=j=0igjgijCij
f f f的轉移複雜一點,列舉子樹大小 j j j i − j i-j ij,那麼子樹 j j j自己的貢獻就是 g j ∗ j ∗ ( n − j ) g_j*j*(n-j) gjj(nj),然後要乘上 g i − j g_{i-j} gij表示每種左子樹形態對應的樹的形態個數。右邊 i − j i-j ij同理,就有轉移方程 f i + 1 = ∑ j = 0 i (   g i g j ( j ∗ ( n − j ) + ( i − j ) ∗ ( n − i + j ) ) + f j ∗ g i − j + f i − j ∗ g j   ) ∗ C i j f_{i+1}=\sum_{j=0}^i(\ g_ig_j(j*(n-j)+(i-j)*(n-i+j))+f_j*g_{i-j}+f_{i-j}*g_j\ )*C_{i}^j fi+1=j=0i( gigj(j(nj)+(ij)(ni+j))+fjgij+fijgj )Cij

時間複雜度 O ( n 2 ) O(n^2) O(n2)


c o d e code code

#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const ll N=2100;
ll n,p,f[N],g[N],c[N][N];
int main()
{
	scanf("%lld%lld",&n,&p);
	g[0]=c[0][0]=1;
	for(ll i=1;i<=n;i++)
		for(ll j=0;j<=i;j++)
			c[i][j]=((j?c[i-1][j-1]:0)+c[i-1][j])%p;
	for(ll i=0;i<n;i++){
		for(ll j=0;j<=i;j++){
			(g[i+1]+=g[j]*g[i-j]%p*c[i][j])%=p;
			(f[i+1]+=(((i-j)*(n-i+j)%p+j*(n-j)%p)*g[j]%p*g[i-j]%p+f[j]*g[i-j]%p+f[i-j]*g[j]%p)%p*c[i][j]%p)%=p;
		}
	}
	printf("%lld\n",f[n]);
	return 0;
}

相關文章