BZOJ 1005 [明明的烦恼]

题面

题意

  给定树上一些节点的度数,对其他节点的度数不做要求,求可能的树的数量。

题解

  考虑求树所对应的 Prufer 序列的数量。Prufer 序列是一种能够完全表示标号无根树的信息的序列,它的构造及还原方式这里略去,只强调它的两个性质:

  • 根据 Prufer 序列的构造与还原方法,含 \(n\;(n\ge 2)\) 个点的标号无根树 \(T\) 与长度为 \(n-2\)\(p_i \in [1,n]\) 的序列 \(\{p_{n-2}\}\) 一一对应。

  • \(T\) 中标号为 \(i\) 的结点度数为 \(d_i\),则 \(i\)\(T\) 对应的 Prufer 序列中出现 \(d_i-1\) 次。

因此,题意相当于给定一些元素在长度为 \(n-2\) 的序列中出现的次数,求可能的序列总数。为每个被限定的数在还没被选中的位置中选择一些位置,最后在空位上随意填上没有被限制的数,用这个思路就可以求出答案。

  Java 在高精度运算方面还是一如既往的方便。

代码

import java.util.*;
import java.math.*;

public class Main{
    public static BigInteger bigint(int n){
        return new BigInteger(String.valueOf(n));
    }
    public static BigInteger C(int n,int m){
        BigInteger ans=bigint(1);
        int i;
        for (i=0;i<m;i++)
            ans=ans.multiply(bigint(n-i)).divide(bigint(i+1));
        return ans;
    }
    public static BigInteger pow(int a,int b){
        BigInteger ans=bigint(1);
        BigInteger mul=bigint(a);
        while (b>0){
            if ((b&1)>0) ans=ans.multiply(mul);
            mul=mul.multiply(mul); b>>=1;
        }
        return ans;
    }
    public static void main(String[] args){
        Scanner in=new Scanner(System.in);
        int i,n,m,k,cnt;
        BigInteger ans=bigint(1);
        n=in.nextInt(); m=n-2; cnt=0;
        if (n==1){
            k=in.nextInt();
            if (k!=0&&k!=-1) System.out.println("0");
            else System.out.println("1");
            in.close();
            return;
        }
        for (i=0;i<n;i++){
            k=in.nextInt();
            if (k==-1){
                cnt+=1; continue;
            }
            ans=ans.multiply(C(m,k-1));
            m-=k-1;
        }
        ans=ans.multiply(pow(cnt,m));
        System.out.println(ans);
        in.close();
    }
}
posted @ 2019-12-08 01:05  Kilo-5723  阅读(105)  评论(0)    收藏  举报