zoukankan      html  css  js  c++  java
  • P4492 [HAOI2018]苹果树

    有一个显然的套路

    (i)的父边对总距离和贡献为(siz_i(n-siz_i))

    在序列问题中有一个非常常见的套路是取任意一个“分割点”然后分别考虑分割点左边和右边的情况,两个乘起来就是我们要求的序列个数

    同理我们在树上也可以采取类似的套路,删掉一条边,考虑分开的两个联通块的方案数,两个乘起来就是合法树的个数了

    考虑(i)子树的情况,从形态讲,树一共会有(siz_i!)种不同形态,从树点编号讲,一共有(large {siz_i-1choose n-i})种编号,已经选了(n-i)个点,选了(i),再选(siz_i-1)

    因为要从上向下生成树,所以保证子树点编号比(i)大来满足,所以子树方案数(large siz_i!{siz_i-1choose n-i})

    考虑子树外的情况

    生成(i)之前共(i!)种不同方式,生成(i)后是不可将点放在(i)子树中,后面的点有((i+1-2),(i+2-2),(i+3-2)...(n-siz_i+1-2))的生成方式

    化简(i(i-1)(n-siz_i-1)!)

    子树外的方案(large siz_i!{siz_i-1choose n-i}i(i-1)(n-siz_i-1)!)

    总方案

    [sum_{i=2}^nsum_{siz=1}^{n-i+1}siz_i!{siz_i-1choose n-i}i(i-1)(n-siz_i-1)! ]

    const int N = 2005;
    ll mod,dp[N][N],fac[N],c[N][N],res;int n;
    int main(){
    	scanf("%d%lld",&n,&mod);fac[0] = 1; dp[1][1] = 1;
    	for(int i = 0;i <= n;++i) c[i][i] = c[0][i] = 1;
    	for(int i = 0;i <= n;++i)
    		for(int j = 1;j < n;++j)
    			c[j][i] = (c[j-1][i-1] + c[j][i-1]) % mod;
    	for(int i = 1;i <= n;++i) fac[i] = fac[i-1] * i % mod;
    	for(int i = 2;i <= n;++i)
    		for(int j = 1;j <= i;++j)
    			dp[i][j] = fac[i-2] * j % mod * (j-1) % mod;
    	for(int i = 2;i <= n;++i)
            for(int j = 1;j <= n-i+1;++j)
                (res += fac[j]*c[j-1][n-i]%mod*j*(n-j)%mod*dp[n-j+1][i]) %= mod;
        printf("%lld",res);
    }
    
  • 相关阅读:
    SpringBoot整合Swagger-ui
    SpringBoot整合Mybatis之Annotation
    Java的四层结构dto、dao、service、controller
    spring boot 项目开发常用目录结构
    Ubuntu Docker-ce安装
    SQL,NoSQL和NewSQL
    Spring常用注解
    JAVA复习重点知识
    谷歌浏览器收藏内容备份
    网线连上显示无网络连接
  • 原文地址:https://www.cnblogs.com/shikeyu/p/13801973.html
Copyright © 2011-2022 走看看