P4492 [HAOI2018]苹果树

思路

题目要求的其实就是每种方案的权值之和(因为每种方案的概率相等)

所以自然想到要求所有的边对最终答案的贡献次数

考虑这一条边被经过了多少次,有这个子树内的点数*子树外的点数次,即\(k\times(n-k)\)

然后考虑总共的中序遍历总共有\(n!\)种,每种方案等概率

先钦定一个点\(i\)(乘上\(i!\)),然后枚举它的\(sz\),这样相当于枚举了每种生成的树的形态,做到了不重不漏

对于这个点\(i\),考虑选择K个点作为它的子树进行统计(\(sz_i=K+1\)),然后选择的k个点的方案数是\(\left(\begin{matrix}n-i\\K\end{matrix}\right)\),这\(K\)个点能构成的树的形态总数有\(K!\)个,然后考虑剩下的\(n-k-i\)个点的分配方案,因为不能放在\(i\)的子树中,所以分配的方案有\((i-1)(i)\dots(n-K-2)\)种(\(n-K-2\)因为只剩一个点,能选择\(n-sz_i-1=n-K-2\)个点),化简一下等于\(\frac{(n-k-2)!}{(i-2)!}\)

然后式子就出来了(注意i从二开始,因为从1开始似乎没有什么意义)

\[\begin{align}ans=&\sum_{i=2}^ni!\sum_{j=1}^{n-i+1}j!\left(\begin{matrix}n-i\\j-1\end{matrix}\right)\frac{(n-j-1)!}{(i-2)!}j(n-j)\\=&\sum_{i=2}^n\sum_{j=1}^{n-i+1}j!\left(\begin{matrix}n-i\\j-1\end{matrix}\right)(n-j-1)!(i-1)ij(n-j)\end{align} \]

然后就很可做了

代码

#include <cstdio>
#include <algorithm>
#include <cstring>
#define int long long
using namespace std;
int n,p,C[2010][2010],jc[2010],ans=0;
signed main(){
    scanf("%d %d",&n,&p);
    jc[0]=1;
    for(int i=1;i<=n;i++)
        jc[i]=(jc[i-1]*i)%p;
    C[0][0]=1;
    for(int i=1;i<=n;i++)
        C[i][0]=C[i][i]=1;
    for(int i=1;i<=n;i++)
        for(int j=1;j<i;j++)
            C[i][j]=(C[i-1][j-1]+C[i-1][j])%p;
    for(int i=2;i<=n;i++)
        for(int j=1;j<=n-i+1;j++)
            ans=(ans+jc[j]*C[n-i][j-1]%p*jc[n-j-1]%p*(i-1)%p*i%p*j%p*(n-j)%p+p)%p;
    printf("%d\n",ans);
    return 0;
}
posted @ 2019-03-18 19:59  dreagonm  阅读(177)  评论(0编辑  收藏  举报