zoukankan      html  css  js  c++  java
  • bzoj1211: [HNOI2004]树的计数(prufer序列+组合数学)

    1211: [HNOI2004]树的计数

    题目:传送门

    题解:

       今天刚学prufer序列,先打几道简单题

       首先我们知道prufer序列和一颗无根树是一一对应的,那么对于任意一个节点,假设这个节点的度数为k,那么在prufer序列里面这个节点就会出现k-1次

       (反过来也同理成立)

       那么具体的原因这里有解释:

       对于任意一个节点在prufer序列里出现一次的话,那么就表示我有一个孩子被删了,那么少了的一次去哪里了呢,因为每次加进去的都是父亲节点,那么少的肯定就是我自己连出去的一条边啊...

       

       知道了这个推论之后,这道题就很简单了:

       题目要求的树必须满足度数的要求,那只要这棵树的prufer序列满足度数要求就ok了啊...

       这样我们就可以用组合数学,直接根据给出的d数组做。

       很容易想到:ans=(n-2)!/(d1-1)!*(d2-1)!....(dn-1)! (如果是入度小于二的话不用计算)

       刚开始傻逼比的打全排列...有重复啊啊啊啊!!!

       最后一点:题目保证方案数不会超过10^17,那long long 肯定没问题啊...可是我们求得是组合,是有除法的(也就是说乘法的时候还是会爆)....ORT那就质因数分解咯...


    代码:

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<cstdlib>
     4 #include<cmath>
     5 #include<algorithm>
     6 typedef long long LL;
     7 using namespace std;
     8 int n;
     9 LL d[210],pr[210];
    10 int s[210];
    11 bool pd(LL x)
    12 {
    13     double t=sqrt(double(x+1));
    14     for(int i=2;i<=t;i++)
    15         if(x%i==0)
    16             return false;
    17     return true;
    18 }
    19 LL p_m(LL a,int b) 
    20 {
    21     LL ans=1;
    22     while(b!=0)
    23     {
    24         if(b%2==1)ans*=a;
    25         b/=2;a*=a;
    26     }
    27     return ans;
    28 }
    29 int main()
    30 {
    31     scanf("%d",&n);int sum=0;
    32     for(int i=1;i<=n;i++){scanf("%d",&d[i]);sum+=d[i];}
    33     if(n==1 && d[1]!=0){printf("0
    ");return 0;}
    34     if(n>1)for(int i=1;i<=n;i++){if(d[i]==0){printf("0
    ");return 0;}}
    35     if(sum-n!=n-2){printf("0
    ");return 0;}
    36     int len=0;
    37     for(LL i=2;i<=150;i++)if(pd(i)==true)pr[++len]=i;
    38     memset(s,0,sizeof(s));
    39     for(int i=1;i<=n-2;i++) 
    40     {
    41         int x=i;
    42         for(int j=1;j<=len;j++)
    43             while(x%pr[j]==0 && x!=0)
    44                 {s[j]++;x/=pr[j];}
    45     }
    46     for(int i=1;i<=n;i++)
    47         for(int k=1;k<=d[i]-1;k++)
    48         {
    49             int x=k;
    50             for(int j=1;j<=len;j++) 
    51                 while(x%pr[j]==0 && x!=0)
    52                     {s[j]--;x/=pr[j];}
    53         }
    54     LL ans=1;
    55     for(int i=1;i<=150;i++)
    56         ans*=p_m(pr[i],s[i]);
    57     printf("%lld
    ",ans);
    58     return 0;
    59 }
  • 相关阅读:
    HAVING 和 WHERE 的使用
    Input and Output
    python数据分析知识点
    正则化
    ol 接入百度地图
    高德室内地图解析
    mapbox 接入高德矢量地图实战
    4、微信小程序和weui
    3、YishaAdmin开源框架搭建
    2、微信小程序开发注册、配置介绍说明
  • 原文地址:https://www.cnblogs.com/CHerish_OI/p/8325361.html
Copyright © 2011-2022 走看看