• Bzoj1005 [HNOI2008]明明的烦恼


    Time Limit: 1 Sec  Memory Limit: 162 MB
    Submit: 4948  Solved: 1926

    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序列对应唯一的树结构这一性质,进行花式组合计算

    为了回避麻烦的高精度除法,可以分解质因数,用减指数代替直接除,最后再把各质数乘起来。

    答案蜜汁长,2000位高精度WA掉了,压了两位就过了。

      1 #include<iostream>
      2 #include<algorithm>
      3 #include<cstring>
      4 #include<cstdio>
      5 #include<cmath>
      6 using namespace std;
      7 const int mxn=1010;
      8 int read(){
      9     int x=0,f=1;char ch=getchar();
     10     while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();}
     11     while(ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();}
     12     return x*f;
     13 }
     14 struct Num{
     15     int x[2001],len;
     16     void read(int a){
     17         len=0;
     18         while(a){x[++len]=a%100;a/=100;}
     19         return;
     20     }
     21     inline int max(int a,int b){return a>b?a:b;}
     22     void operator * (int b){
     23         for(int i=1;i<=len;i++)
     24             x[i]*=b;
     25         for(int i=1;i<=len;i++)
     26             if(x[i]>9){
     27                 x[i+1]+=x[i]/100;
     28                 x[i]%=100;
     29                 len=max(len,i+1);
     30             }
     31         return;
     32     }
     33 }a;
     34 void Print(Num a){
     35     while(!a.x[a.len])a.len--;
     36     for(int i=a.len;i;i--)
     37         if(i==a.len)printf("%d",a.x[i]);
     38         else printf("%02d",a.x[i]);
     39     puts("");
     40     return;
     41 }
     42 int pri[mxn],cnt=0;
     43 bool vis[mxn];
     44 void init(){
     45     for(int i=2;i<mxn;i++){
     46         if(!vis[i])pri[++cnt]=i;
     47         for(int j=1;j<=cnt && pri[j]*i<mxn;j++){
     48             vis[pri[j]*i]=1;
     49             if(i%pri[j]==0)break;
     50         }
     51     }
     52     return;
     53 }
     54 int p[mxn],d[mxn],n,m,smm=0;
     55 void calc(int x,int f){
     56 //    printf("calc:%d %d
    ",x,f);
     57     for(int i=1;i<=cnt && pri[i]<=x;i++){
     58         while(x%pri[i]==0){
     59             p[i]+=f;
     60             x/=pri[i];
     61         }
     62     }
     63     return;
     64 }
     65 int main(){
     66 //    freopen("bzoj_100511.in","r",stdin);
     67 //    freopen("bzoj_1005.out","w",stdout);
     68     int i,j;
     69     init();
     70     n=read();
     71     if(n==1){
     72         i=read();
     73         if(!i || i==-1)printf("1
    ");
     74         else printf("0
    ");
     75         return 0;
     76     }
     77     for(i=1;i<=n;i++){
     78         d[i]=read();
     79         if(!d[i]){
     80             printf("0
    ");return 0;
     81         }
     82         if(d[i]!=-1)smm+=d[i]-1;
     83         else m++;
     84     }
     85     if(smm>n-2 || !m){
     86         printf("0
    ");return 0;
     87     }
     88     for(i=n-2;i>1;i--)calc(i,1);
     89     calc(m,n-2-smm);
     90     for(i=n-2-smm;i>1;i--)calc(i,-1);
     91     for(i=1;i<=n;i++){
     92         for(j=d[i]-1;j>1;j--){
     93             calc(j,-1);
     94         }
     95     }
     96     a.read(1);
     97     for(i=1;i<=cnt;i++){
     98         for(j=1;j<=p[i];j++)
     99             a.operator *(pri[i]);
    100     }
    101     Print(a);
    102     return 0;
    103 }
  • 相关阅读:
    如果再回到从前 备忘录模式
    在NBA我需要翻译 适配器模式
    无尽加班何时休 状态模式
    Linux网络编程学习(六) ----- 管道(第四章)
    Linux网络编程学习(五) ----- 信号(第四章)
    Linux网络编程学习(四) -----守护进程的建立(第三章)
    Linux网络编程学习(三) ----- 进程控制实例(第三章)
    Linux网络编程学习(二) ----- 进程控制(第三章)
    Linux网络编程学习(一) ----- 概论和Linux模型(第一章第二章)
    Linux网络编程学习计划
  • 原文地址:https://www.cnblogs.com/SilverNebula/p/6719750.html
Copyright © 2020-2023  润新知