zoukankan      html  css  js  c++  java
  • 【bzoj1005】【hnoi2008】明明的烦恼

    Time Limit: 1 Sec  Memory Limit: 162 MB
    Submit: 6660  Solved: 2624
    [Submit][Status][Discuss]

    Description

      自从明明学了树的结构,就对奇怪的树产生了兴趣......给出标号为1到N的点,以及某些点最终的度数,允许在
    任意两点间连线,可产生多少棵度数满足要求的树?

    Input

      第一行为N(0 < N < = 1000),
    接下来N行,第i+1行给出第i个节点的度数Di,如果对度数不要求,则输入-1

    Output

      一个整数,表示不同的满足要求的树的个数,无解输出0

    Sample Input

    3

    1

    -1

    -1

    Sample Output

    2

    HINT

     

      两棵树分别为1-2-3;1-3-2

     

    Source

     
    [Submit][Status][Discuss]

     

    题意:求一种有编号的树的方案,这棵树有些点有度数限制,有些点没有;

    题解:

          首先要知道prufer序列(推荐:http://www.cnblogs.com/zhj5chengfeng/p/3278557.html

          (prufer的u上面好像还有两个点来着,懒得打了)

         1.构造prufer:
         每次选一个编号最小的叶子结点删除,同时把和它相连的那个点加入prufer序列,更新原图的度数,直到剩下两个点;

         这可以用一个set来实现;

         这样n个点的树的prufer长度为n-2,同时一个点的度数=在prufer序列里出现的次数+1;

         2.由prufer序列还原树:
         由上面的结论可以还原出点的度数,考虑prufer序列的每个点是如何被加进来的,
    维护最小叶节点就可以按照生成的方式还原树;

         每一个树对应一个唯一的prufer,反过来也是;

         所以我们说长度为n-2 的prufer序列和编号为1-n的树一一对应;

         3.所以编号为1-n的数的个数为$n^{n-2}$ ;

           加上度数的限制呢,假设每个点度数为di: $frac{n^{n-2}}{Pi (d_i – 1) }$

           如果是像题目,仅有一些点有度数限制,考虑先排好有限制的点,选其他位置:(记有度数限制的点有$cnt$个,同时$sum=sum_{i=1}^{cnt}(d_i - 1)$ )
           $$C_{n-2}^{sum} frac{sum!}{ Pi_{i=1}^{cnt} {(d_i – 1)} } (n-cnt)^{n-2-sum}$$

           $$frac{ (n-2)! } { (n-2-sum)! Pi{ (d_i – 1)! } } (n-cnt)^{n-sum-2} $$

           需要高精度,但是可以用勒让德定理质因数分解代替中间部分的高精度,最后统一写个高精乘法。

      1 #include<cstdio>
      2 #include<iostream>
      3 #include<algorithm>
      4 #include<cstring>
      5 #include<queue>
      6 #include<cmath>
      7 #include<vector>
      8 #include<stack>
      9 #include<map>
     10 #define Run(i,l,r) for(int i=l;i<=r;i++)
     11 #define Don(i,l,r) for(int i=l;i>=r;i--)
     12 #define ll long long
     13 #define inf 0x3f3f3f3f
     14 using namespace std;
     15 const int N = 1010,base = 10000;
     16 int n,sum,cnt,pri[N],now[N],vis[N],sz,d[N];
     17 void pre(){
     18     for(int i=2;i<=1e3;i++){
     19         if(!vis[i])pri[++sz] = i;
     20         for(int j=1;j<=sz&&i*pri[j]<=1e3;j++){
     21             vis[i*pri[j]] = 1;
     22             if(i % pri[j]==0)break;
     23         }
     24     }
     25 }
     26 void get_num(int x,int y){
     27     if(!x)return;
     28     int tmp = x;
     29     for(int i=1;i<=sz;i++){
     30         while(tmp%pri[i]==0&&(tmp/=pri[i]))now[i]+=y; 
     31     }
     32 }
     33 void get_fac(int x,int y){
     34     for(int i=1;i<=sz;i++){
     35         int tmp = x;
     36         while(tmp){
     37             now[i]+= tmp/pri[i] * y; 
     38             tmp/=pri[i];
     39         }
     40     }
     41 }
     42 struct Bign{
     43     int len,c[1000]; 
     44     Bign(){len=0;memset(c,0,sizeof(c));}
     45     void zero(){while(len&&!c[len])len--;}
     46     void print(){
     47         zero();
     48         printf("%d",c[len]);
     49         Don(i,len-1,0)printf("%04d",c[i]);
     50         puts("");
     51     }
     52     Bign operator = (const int&A){
     53         len=0; c[0]=A;
     54         return *this;
     55     }
     56     Bign operator * (const int&A){
     57         Bign ret;
     58         ret.len = len + 1;
     59         for(int i=0;i<=len;i++){
     60             ret.c[i] += c[i] * A;
     61         } 
     62         for(int i=0;i<=ret.len;i++){
     63             if(ret.c[i]>=base){
     64                 ret.c[i+1] += ret.c[i] / base;
     65                 ret.c[i] %= base;
     66             }
     67         }
     68         ret.zero();
     69         return ret;
     70     }   
     71     Bign operator * (const Bign&A){
     72         Bign ret;
     73         ret.len = len + A.len + 1;
     74         for(int i=0;i<=len;i++)
     75         for(int j=0;j<=A.len;j++){
     76             ret.c[i+j] += c[i] * A.c[j];
     77             if(ret.c[i+j]>=base){
     78                 ret.c[i+j+1] += ret.c[i+j] / base;
     79                 ret.c[i+j] %= base;
     80             }
     81         } 
     82         for(int i=0;i<=ret.len;i++){
     83             if(ret.c[i]>=base){
     84                 ret.c[i+1] += ret.c[i] / base;
     85                 ret.c[i] %= base;
     86             }
     87         }
     88         ret.zero();
     89         return ret;
     90     }   
     91 };
     92 int main(){
     93 //  freopen("bzoj1005.in","r",stdin);
     94 //  freopen("bzoj1005.out","w",stdout);
     95     pre();
     96     scanf("%d",&n);
     97     for(int i=1;i<=n;i++){
     98         scanf("%d",&d[i]);
     99         if(~d[i]){
    100             cnt++;
    101             sum+=(d[i]-1);
    102         }
    103     }
    104     if(sum>n-2){puts("0");return 0;} 
    105     get_fac(n-2,1); 
    106     get_fac(n-2-sum,-1);
    107     for(int i=1;i<=n;i++)if(~d[i]){
    108         get_fac(d[i] - 1 , -1);
    109     }
    110     get_num(n - cnt , n - 2 - sum);
    111     Bign ans;
    112     ans = 1;
    113     for(int i=1;i<=sz;i++)if(now[i]){
    114         Bign tmp; tmp = 1;
    115         for(int j=1;j<=now[i];j++)tmp = tmp * pri[i];
    116         //tmp.print();
    117         ans = ans * tmp;
    118     }
    119     ans.print();
    120     return 0;
    121 }//by tkys_Austin;
    View Code

     

     

  • 相关阅读:
    LeetCode
    LeetCode
    ELK系列(5)
    ELK系列(4)
    ELK系列(3)
    ELK系列(2)
    ELK系列(1)
    计算机网络常见面试题总结
    mosquitto启动时Address already in use 和 一般的 Address already in use
    size和STL中的size_type
  • 原文地址:https://www.cnblogs.com/Paul-Guderian/p/9834444.html
Copyright © 2011-2022 走看看