• [HAOI2018]苹果树


    [HAOI2018]苹果树

    题目大意:

    一个(n(nle2000))个点的二叉树,初始时只有一个根结点(1)。按顺序加入(2sim n)的结点。每次随机一个未拓展的分支加入一个新的结点。求最后树上所有点对之间的距离之和的期望(E imes n!)(p(ple10^9+7))取模的结果。

    思路:

    对于(n)个点的二叉树,加入点(1)时有(1)个分支可以加,加入点(2)时有(2)个分支可以加,以此类推,加入点(n)时有(n)个分支可以加。每加入一个点会在覆盖掉原来一个分支的基础上增加两个分支。因此若考虑结点编号的不同,(n)个结点的二叉树有(n!)种形态。

    将问题转化为加入一条边后,每条边对答案的贡献。若树的形态确定,考虑经过一条边的点对,若在树上去掉这条边,将树分为大小分别为(j)(n-j)的两个连通块,则这条边对答案有(n(n-j))的贡献。

    然而,现在树的形态是不确定的。对于现在加入第(i-1)条边,我们不妨枚举边下端的子树大小(j)。显然若在子树内结点编号确定的情况下,共有(j!)种子树。子树的根结点一定是(i),从(n-i)个结点中选择(j-1)个作为子树中的结点,总共有(inom{n-i}{j-1})种方法。

    对于编号为(1sim i)的点,共有(i!)种生成方式。对于剩下的(n-j-i+1)个结点,由于不能让它们加到(i)的子树中,因此他们分别有((i-1),i,ldots,(n-j-1))种方法可以加。也就是说,算上前面(i!)个点,子树外共有((n-j-1)!cdot icdot(i-1))种方法。

    答案即为(sum_{i=2}^nsum_{j=1}^{n-i+1}j!cdotinom{n-i}{j-1}cdot jcdot(n-j)!cdot icdot(i-1))

    时间复杂度(mathcal O(n^2))

    源代码:

    #include<cstdio>
    #include<cctype>
    typedef long long int64;
    inline int getint() {
    	register char ch;
    	while(!isdigit(ch=getchar()));
    	register int x=ch^'0';
    	while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
    	return x;
    }
    const int N=2001;
    int n,mod,fac[N],c[N][N];
    int main() {
    	n=getint(),mod=getint();
    	for(register int i=c[0][0]=1;i<=n;i++) {
    		for(register int j=c[i][0]=1;j<=i;j++) {
    			c[i][j]=(c[i-1][j-1]+c[i-1][j])%mod;
    		}
    	}
    	for(register int i=fac[0]=1;i<=n;i++) {
    		fac[i]=(int64)fac[i-1]*i%mod;
    	}
    	int ans=0;
    	for(register int i=2;i<=n;i++) {
    		for(register int j=1;j<=n-i+1;j++) {
    			(ans+=(int64)j*fac[j]%mod*c[n-i][j-1]%mod*fac[n-j]%mod*i*(i-1)%mod)%=mod;
    		}
    	}
    	printf("%d
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    Linux文件和目录
    Android/ios手机销售榜
    项目开发流程
    游戏签到系统测试点
    项目上线后出现问题,该如何解决?
    公交地铁出行测试点
    初学测试
    测试用例的优先级
    Django的MVT模式与MVC模式
    JWT安装配置
  • 原文地址:https://www.cnblogs.com/skylee03/p/9168564.html
Copyright © 2020-2023  润新知