bzoj1005: [HNOI2008]明明的烦恼 prufer序列

https://www.lydsy.com/JudgeOnline/problem.php?id=1005

给出标号为1到N的点,以及某些点最终的度数,允许在任意两点间连线,可产生多少棵度数满足要求的树?

题解:prufer序列,prufer序列是一种无根树的编码表示,对于一棵n个节点带编号的无根树,对应唯一一串长度为n-2的prufer编码。

prufer序列中某个编号出现的次数就等于这个编号的节点在无根树中的度数-1

所以一张n个点的无向完全图有n^(n-2)个生成树(长度为n-2的数列,每个地方有n种放法)

n个节点度依次为d1.d2.......dn,无根树一共有(n-2)!/(d1-1)!*(d2-1)!....*(dn-1)!,   即点的数量固定(di-1),要求放法不一样,全排列除上每种点重复的放法

对于该题,剩余的点left为n-2-di(di!=-1),一共有(n-2)!/(di-1)!*...*left!,  然后left每个有m(di==-1的点)中可以放的点,就是m^left中方法

最后答案就是(n-2)/(di-1)!。。。。*m^(left)

/**************************************************************
    Problem: 1005
    User: walfy
    Language: Java
    Result: Accepted
    Time:1432 ms
    Memory:20500 kb
****************************************************************/
 
import java.math.BigInteger;
import java.util.Scanner;
 
 
public class Main {
 
    /**
     * @param args
     */
    static BigInteger [] fac = new BigInteger [1000+10];
    static void init()
    {
        fac[0] = BigInteger.ONE;
        for(int i=1;i<=1000;i++)
        {
            fac[i]=fac[i-1].multiply(BigInteger.valueOf(i));
        }
    }
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Scanner cin = new Scanner(System.in);
        init();
        int n = cin.nextInt();
        int [] d = new int[1000+10];
        int sum = 0,num = 0;
        BigInteger ans = fac[n-2];
        for(int i=1;i<=n;i++)
        {
            d[i] = cin.nextInt();
            if(d[i]!=-1)
            {
                sum += d[i]-1;
                ans=ans.divide(fac[d[i]-1]);
            }
            else num++;
        }
        int left = n-2-sum;
        ans = ans.divide(fac[left]);
        ans = ans.multiply(BigInteger.valueOf(num).pow(left));
        System.out.println(ans);
    }
 
}
View Code

 

转载于:https://www.cnblogs.com/acjiumeng/p/8966058.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值