【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

 

 

 

 

posted @ 2018-10-23 07:45  大米饼  阅读(160)  评论(0编辑  收藏  举报