首先有个很奇妙而且很有用的性质:每个二叉树对应唯一的中序遍历,然后每个二叉树出现概率相同。所以n个节点的二叉树形态是n!种(题目中说了*n!已经是提示了),对每种方案求和即可得到期望。令f[i]表示i个节点的子树,根深度为1时,所有点的期望深度之和乘i!的值,令g[i]表示i个节点的子树,期望两两路径之和乘i!的值。
然后得到f[i]=i*i!+ΣC(i-1,L)(f[L]*R!+f[R]*L!),g[i]=ΣC(i-1,L)(g[L]*R!+g[R]*L!+f[L]*R!*(R+1)+f[R]*L!*(L+1)),其中0<=L<i,L、R为左/右子树大小,只需要枚举L即可(因为R=i-1-L),复杂度O(n2)
这题这么水的吗qwq?其实当模数做NTT时,貌似可以分治NTT优化O(nlog2n),反正我不会就不管了。
#include<bits/stdc++.h> using namespace std; const int N=2019; int n,mod,c[N][N],fac[N],f[N],g[N]; int main() { scanf("%d%d",&n,&mod); fac[0]=c[0][0]=1; for(int i=1;i<=n;i++) { c[i][0]=1,fac[i]=1ll*fac[i-1]*i%mod; for(int j=1;j<=i;j++)c[i][j]=(c[i-1][j-1]+c[i-1][j])%mod; } f[1]=1; for(int i=2;i<=n;i++) { for(int L=0;L<i;L++) { int R=i-1-L,F,G; F=(1ll*f[L]*fac[R]+1ll*f[R]*fac[L])%mod; G=(1ll*f[L]*fac[R]%mod*(R+1)+1ll*f[R]*fac[L]%mod*(L+1)+1ll*g[L]*fac[R]+1ll*g[R]*fac[L])%mod; f[i]=(f[i]+1ll*F*c[i-1][L])%mod; g[i]=(g[i]+1ll*G*c[i-1][L])%mod; } f[i]=(f[i]+1ll*i*fac[i])%mod; } printf("%d",g[n]); }