正题
题目链接:https://www.luogu.com.cn/problem/P4492
题目大意
开始有一个节点,第iii次在一个儿子不超过222的节点下面长出一个新儿子编号为iii。求所有方案下树的路径长度和。
解题思路
考虑计算每条边的贡献,设gig_igi表示大小为iii的树的形态个数,fif_ifi表示所有大小为iii的树的路径长度和。然后题目给出的要求就是子节点编号比父节点大。
那么ggg有转移gi+1=∑j=0igjgi−jCijg_{i+1}=\sum_{j=0}^ig_jg_{i-j}C_{i}^jgi+1=j=0∑igjgi−jCij
fff的转移复杂一点,枚举子树大小jjj和i−ji-ji−j,那么子树jjj自己的贡献就是gj∗j∗(n−j)g_j*j*(n-j)gj∗j∗(n−j),然后要乘上gi−jg_{i-j}gi−j表示每种左子树形态对应的树的形态个数。右边i−ji-ji−j同理,就有转移方程fi+1=∑j=0i(gigj(j∗(n−j)+(i−j)∗(n−i+j))+fj∗gi−j+fi−j∗gj)∗Cijf_{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}^jfi+1=j=0∑i( gigj(j∗(n−j)+(i−j)∗(n−i+j))+fj∗gi−j+fi−j∗gj )∗Cij
时间复杂度O(n2)O(n^2)O(n2)
codecodecode
#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;
}