zoukankan      html  css  js  c++  java
  • BZOJ 1005 [HNOI2008]明明的烦恼

    1005: [HNOI2008]明明的烦恼

    Time Limit: 1 Sec  Memory Limit: 162 MB
    Submit: 3108  Solved: 1248
    [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

    题解:天哪。。这要是在考场上怎么想得完,蒟蒻做不到。。。

    用到了prufer数列,以下摘自度娘:

    Prufer数列是无根树的一种数列。在组合数学中,Prufer数列由有一个对于顶点标过号的树转化来的数列,点数为n的树转化来的Prufer数列长度为n-2。它可以通过简单的迭代方法计算出来。它由Heinz Prufer于1918年在证明cayley定理时首次提出。

    1将树转化成Prufer数列的方法

    一种生成Prufer序列的方法是迭代删点,直到原图仅剩两个点。对于一棵顶点已经经过编号的树T,顶点的编号为{1,2,...,n},在第i步时,移去所有叶子节点(度为1的顶点)中标号最小的顶点和相连的边,并把与它相邻的点的编号加入Prufer序列中,重复以上步骤直到原图仅剩2个顶点。
    例子
    Prufer数列Prufer数列
    以右边的树为例子,首先在所有叶子节点中编号最小的点是2,和它相邻的点的编号是3,将3加入序列并删除编号为2的点。接下来删除的点是4,5被加入序列,然后删除5,1被加入序列,1被删除,3被加入序列,此时原图仅剩两个点(即3和6),Prufer序列构建完成,为{3,5,1,3}

    2将Prufer数列转化成树的方法

    设{a1,a2,..an-2}为一棵有n个节点的树的Prufer序列,另建一个集合G含有元素{1..n},找出集合中最小的未在Prufer序列中出现过的数,将该点与Prufer序列中首项连一条边,并将该点和Prufer序列首项删除,重复操作n-2次,将集合中剩余的两个点之间连边即可。
    例子
    仍为上面的树,Prufer序列为{3,5,1,3},开始时G={1,2,3,4,5,6},未出现的编号最小的点是2,将2和3连边,并删去Prufer序列首项和G中的2。接下来连的边为{4,5},{1,5},{1,3},此时集合G中仅剩3和6,在3和6之间连边,原树恢复。
     
    以下摘自怡红公子:该题需要将树转化为prufer编码:
     n为树的节点数,d[ ]为各节点的度数,m为无限制度数的节点数。
    则            
    所以要求在n-2大小的数组中插入tot各序号,共有种插法;
    在tot各序号排列中,插第一个节点的方法有种插法;
                               插第二个节点的方法有种插法;
                                          .........
    另外还有m各节点无度数限制,所以它们可任意排列在剩余的n-2-tot的空间中,排列方法总数为
     
    根据乘法原理:
     
     
    然后就要高精度了.....但高精度除法太麻烦了,显而易见的排列组合一定是整数,所以可以进行质因数分解,再做一下相加减。
     
     
    关于n!质因数分解有两种方法,第一种暴力分解,这里着重讲第二种。
      若p为质数,则n!可分解为 一个数*,其中  <n
     
    所以 
     
    ------------------------------------------------------------------------------------------------------------------------------
    然后呢。。。貌似就可以做了?
    不过写起来还是很hentai的。。。高精度最hentai。。。我才不是复制的。。。
      1 #include<iostream>
      2 #include<cstdio>
      3 #include<cmath>
      4 #include<algorithm>
      5 #include<queue>
      6 #include<cstring>
      7 #define PAU putchar(' ')
      8 #define ENT putchar('
    ')
      9 using namespace std;
     10 const int maxn=1000+10,maxm=10000+10,inf=-1u>>1;
     11 const int MAXN=3010;
     12 struct bign{
     13     int len,s[MAXN];  
     14     bign(){memset(s,0,sizeof(s));len=1;}
     15     bign(int num){*this=num;}
     16     bign(const char *num){*this=num;}
     17     bign operator = (const int num){
     18         char s[MAXN];  sprintf(s,"%d",num);  
     19         *this = s;return *this;
     20     }
     21     bign operator = (const char *num){
     22         for(int i=0;num[i]=='0';num++);
     23         len=strlen(num);  
     24         for(int i=0;i<len;i++) s[i]=num[len-i-1]-'0';  
     25         return *this;
     26     }
     27     bign operator + (const bign &b) const{
     28         bign c;c.len=0;
     29         for(int i=0,g=0;g||i<max(len,b.len);i++)  {
     30             int x=g;
     31             if(i<len) x+=s[i];  
     32             if(i<b.len) x+=b.s[i];
     33             c.s[c.len++]=x%10;  
     34             g=x/10;
     35         } return c;  
     36     }
     37     void clean(){while(len > 1 && !s[len-1]) len--;return;}
     38     bign operator * (const bign &b){
     39         bign c;
     40         c.len=len+b.len;  
     41         for(int i=0;i<len;i++) for(int j=0;j<b.len;j++) c.s[i+j]+=s[i]*b.s[j];  
     42         for(int i=0;i<c.len;i++){
     43             c.s[i+1]+=c.s[i]/10;  
     44             c.s[i]%=10;
     45         } c.clean();return c;  
     46     }
     47     bign operator - (const bign &b){
     48         bign c;c.len=0;
     49         for(int i=0,g=0;i<len;i++){
     50             int x=s[i]-g;if(i<b.len) x-=b.s[i];  
     51             if(x>=0) g=0;  
     52             else g=1,x+=10;
     53             c.s[c.len++]=x;
     54         } c.clean();return c;  
     55     }
     56     bool operator < (const bign &b)  {
     57         if(len!=b.len) return len<b.len;  
     58         for(int i=len-1;i>=0;i--){
     59             if(s[i]!=b.s[i]) return s[i]<b.s[i];  
     60         } return false;
     61     }
     62     bool operator > (const bign &b){
     63         if(len!=b.len) return len>b.len;  
     64         for(int i=len-1;i>=0;i--){
     65             if(s[i]!=b.s[i]) return s[i]>b.s[i];  
     66         } return false;  
     67     }
     68     bool operator == (const bign &b){
     69         return !(*this>b)&&!(*this<b);  
     70     }
     71     void print(){
     72         for(int i=len-1;i>=0;i--) putchar(s[i]+'0');return;
     73     }
     74 }ans;
     75 bign pow(int x0,int y){
     76     bign x=x0,ans=1;for(int i=y;i;i>>=1,x=x*x)if(i&1)ans=ans*x;return ans;
     77 }
     78 int n,m,tot=0,fenmu[maxn],fenzi[maxn];bool prime[maxn];
     79 void initp(){
     80      memset(prime,true,sizeof(prime));prime[0]=prime[1]=false;prime[2]=true;
     81      for(int i=2;i*i<=n;i++)if(prime[i])for(int j=i*i;j<=n;j+=i)prime[j]=false;
     82 }
     83 void split(int t,int a[]){
     84     int sum;for(int i=2;i<=t;i++)if(prime[i]){
     85         sum=i;while(sum<=t)a[i]+=t/sum,sum*=i;
     86     }return;
     87 }
     88 inline int read(){
     89     int x=0,sig=1;char ch=getchar();
     90     while(!isdigit(ch)){if(ch=='-')sig=-1;ch=getchar();}
     91     while(isdigit(ch))x=10*x+ch-'0',ch=getchar();
     92     return x*=sig;
     93 }
     94 inline void write(int x){
     95     if(x==0){putchar('0');return;}if(x<0)putchar('-'),x=-x;
     96     int len=0,buf[15];while(x)buf[len++]=x%10,x/=10;
     97     for(int i=len-1;i>=0;i--)putchar(buf[i]+'0');return;
     98 }
     99 void init(){
    100     n=read();initp();int d;
    101     for(int i=1;i<=n;i++){
    102           d=read();
    103           if(d<0){m++;continue;}
    104           if(d>1)split(d-1,fenmu);
    105           tot+=d-1;
    106     }split(n-2-tot,fenmu);split(n-2,fenzi);
    107     return;
    108 }
    109 void work(){
    110     for(int i=1;i<=1000;i++)fenzi[i]-=fenmu[i];ans=1;
    111     for(int i=1;i<=1000;i++)if(fenzi[i])ans=ans*pow(i,fenzi[i]);
    112     if(m)ans=ans*pow(m,n-2-tot);
    113     if(tot>n-2||(tot<n-2&&!m)){write(0);return;}
    114     return;
    115 }
    116 void print(){
    117     ans.print();
    118     return;
    119 }
    120 int main(){init();work();print();return 0;}
  • 相关阅读:
    模板模式变形
    理解volatitle带来的可见性
    数据库隔离级别
    Spring对POST内容进行处理的坑
    动态加载JS和CSS
    MySQL性能优化总结
    JS自执行匿名函数
    CDATA为何物?
    如何编写高效的jQuery代码
    war和war exploded区别
  • 原文地址:https://www.cnblogs.com/chxer/p/4639448.html
Copyright © 2011-2022 走看看