Luogu4492

思路

事实 \(1\)\(n\) 个结点的二叉树剩余分支有 \(n+1\) 个。

这个事实使用数学归纳法不难得证。

事实 \(2\):按如此方案生成的二叉树有 \(n!\) 种,且每种左右子树大小分配方案各 \((n-1)!\) 种。

前一句是可以用事实 \(1\) 立刻得到的,考虑后一句是什么意思。

即,记左子树大小为 \(l\),则有方案数为 \(\binom{n-1}{l}l!(n-l-1)!\),也就是 \((n-1)!\)

这个柿子 \(\binom{n-1}{l}l!(n-l-1)!\) 枚举哪些点分入左子树,再枚举左右子树形态既得。

记对所有这样的树,其到根距离之和为 \(f_n\),点间距离之和为 \(g_n\)

规定 \(f_0=g_0=0\)

分别直接枚举左子树大小即得递推方程。

\[\\ f_n=\sum_{i=0}^{n-1}\binom{n-1}{i}(f_i(n-i-1)!+f_{n-i-1}i!+i!(n-i-1)!i+i!(n-i-1)!(n-i-1)) \\=n!(n-1)+(2\sum_{i=0}^{n-1}\binom{n-1}{i}(n-i-1)!f_i) \\\]

\(g\),我们在根节点统计 LCA 为当前结点的方案数。

\[\\ g_n=f_n+\sum_{i=0}^{n-1}\binom{n-1}{i}(g_i(n-i-1)!+g_{n-i-1}i!+(f_i+i!i)(n-i-1)!(n-i-1)+(f_{n-i-1}+(n-i-1)!(n-i-1))i!i) \\=f_n+2\sum_{i=0}^{n-1}\binom{n-1}{i}g_i(n-i-1)!+2\sum_{i=0}^{n-1}\binom{n-1}{i}f_i(n-i-1)!(n-i-1)+2(n-1)!\sum_{i=0}^{n-1}i(n-i-1) \\\]

手算前几项:

\[f:\left<0,0,2,16,\cdots\right> \]

\[g:\left<0,0,2,24,\cdots\right> \]

符合样例。

这样就足够 \(O(n^2)\) 了。

注意组合数要 \(O(n^2)\) 递推预处理

Code

modint C[2005][2005],A[2005];
modint F[2005],G[2005];
int main()
{
    uint n;ullt p;scanf("%u%llu",&n,&p);
    AnyMod::ChgMod(p);
    C[0][0]=1;
    for(uint i=1;i<=n;i++)
    {
        C[i][0]=1;for(uint j=1;j<=i;j++)C[i][j]=C[i-1][j-1]+C[i-1][j];
    }
    A[0]=1;for(uint i=1;i<=n;i++)A[i]=A[i-1]*i;
    for(uint i=1;i<=n;i++)
    {
        for(uint j=0;j<i;j++)F[i]+=C[i-1][j]*F[j]*A[i-j-1];
        F[i]*=2;
        F[i]+=A[i]*(i-1);
    }
    for(uint i=1;i<=n;i++)
    {
        for(uint j=0;j<i;j++)G[i]+=C[i-1][j]*G[j]*A[i-j-1];
        for(uint j=0;j<i;j++)G[i]+=C[i-1][j]*F[j]*A[i-j-1]*(i-j-1);
        for(uint j=0;j<i;j++)G[i]+=A[i-1]*j*(i-j-1);
        G[i]*=2;
        G[i]+=F[i];
    }
    G[n].println();
    return 0;
}
posted @ 2022-07-13 08:18  myee  阅读(15)  评论(0编辑  收藏  举报