• 「BZOJ1005」[HNOI2008] 明明的烦恼


    「BZOJ1005」[HNOI2008] 明明的烦恼

    先放几个prufer序列的结论:

    Prufer序列是一种对有标号无根树的编码,长度为节点数-2。 

    具体存在无根树转化为prufer序列和prufer序列转化为无根树两种操作:

    无根树转化为prufer序列 1、找到编号最小的度数为1的点 2、删除该节点并在序列中添加与该节点相连的节点的编号 3、重复1,2操作,直到整棵树只剩下两个节点

    prufer序列转化为无根树 设prufer序列为M,另一个集合G={1,2…n} 每次提取M中最靠前的元素u与G中不存在与M且最靠前的元素v,将u与v连边,分别在两个集合中删除u、v。 最后G中剩下两个元素,将这两个点连边。

    Prufer序列中某个编号出现的次数等于这个编号的节点在无根树中的度数-1 。  一棵n个节点的无根树唯一地对应了一个长度为n-2的数列,数列中的每个数都在1到n的范围内

    有关性质的应用 n个点构成的无根树的个数: $n^(n-2)$ 确定n个点度数分别为d1,d2…时无根树个数: $(n-2)!/((d1-1)!*(d2-1)!*…)$ n个点的

    有标号有根树的个数: $n*n^{n-2}=n^{n-1}$

    然后看这个题:

    有某些点知道度数,那么先把这些点放到prufer序列中,设num为度数大于0的点数,fnum为已知度数的点出现次数总和,

    方案数C_{n-2}^{fnum}*(n-2)!/((d1-1)!*(d2-1)!*…),然后把剩下的序列填满,每个序列有n-num种情况,乘法计数原理成起来即${n-num}^{n-2-fnum}$,最后将两部分乘起来即可。(这个题也用到了高精……)

     1 #include<algorithm>
     2 #include<cstring>
     3 #include<iostream>
     4 #include<cstdio>
     5 using namespace std;
     6 #define ma(x) memset(x,0,sizeof(x))
     7 int n,d[1010],num,fnum;
     8 struct sz
     9 {
    10     int a[20000];
    11 }a;
    12 sz mul(sz &a,int b)
    13 {
    14     sz c;ma(c.a);
    15     c.a[0]=a.a[0];
    16     for(int i=1;i<=a.a[0];i++)
    17     c.a[i]=a.a[i]*b;
    18     for(int i=1;i<=c.a[0];i++)
    19     if(c.a[i]>=10)
    20     {
    21         c.a[i+1]+=c.a[i]/10;
    22         c.a[i]%=10;
    23         if(i==c.a[0])c.a[0]++;
    24     }
    25     return c;
    26 }
    27 sz div(sz &a,int b)
    28 {
    29     sz ans;ma(ans.a);
    30     int yu=0;
    31     for(int i=1;i<=a.a[0];i++)    
    32     {
    33         yu=yu*10+a.a[i];
    34         if(yu/b>0)
    35         {
    36             ans.a[++ans.a[0]]=yu/b;
    37             yu%=b;
    38         }
    39         else if(ans.a[0])ans.a[0]++;
    40     }
    41     return ans;
    42 }
    43 void print(sz &a)
    44 {
    45     for(int i=1;i<=a.a[0];i++)cout<<a.a[i];
    46     puts("");
    47 }
    48 bool cmp(int a,int b){return a>b;}
    49 signed main()
    50 {
    51     cin>>n;
    52     for(int i=1;i<=n;i++)
    53     {
    54         cin>>d[i];
    55         if(d[i]>-1)num++;
    56         if(d[i]>=2)fnum+=d[i]-1;
    57         if((d[i]==0&&n!=1)||d[i]>=n||(d[i]!=0&&n==1)){puts("0");return 0;}
    58     }
    59     a.a[0]=a.a[1]=1;
    60     for(int i=2;i<=n-2;i++)a=mul(a,i);//(n-2)!
    61     sort(d+1,d+n+1,cmp);
    62     reverse(a.a+1,a.a+a.a[0]+1);
    63     for(int i=1;i<=num;i++)//(d[i]-1)!
    64         for(int j=2;j<d[i];j++)
    65             a=div(a,j);
    66     for(int i=2;i<=n-2-fnum;i++)a=div(a,i);//(n-2-fnum)!
    67     reverse(a.a+1,a.a+a.a[0]+1);
    68     for(int i=1;i<=n-2-fnum;i++)
    69             a=mul(a,n-num);
    70     reverse(a.a+1,a.a+a.a[0]+1);
    71     print(a);
    72 }
    View Code

     

     

  • 相关阅读:
    Hadoop之Linux源代码编译
    《程序猿的修炼——从优秀到卓越》读书笔记(二)——运营和项目管理
    WPF文字渲染相关的问题及解决
    APNS push server端 SSL3.0 转 TLS (iPhone苹果推送服务)
    14西安区域赛总结帖
    linux内核调试+qemu+eclipse【转】
    一步一步粗谈linux文件系统(三)----超级块(superblock)【转】
    block(data block,directory block)、inode、块位图、inode位图和super block概念详解【转】
    Linux文件系统及文件储存方式【转】
    简单虚拟文件系统的设计与实现【转】
  • 原文地址:https://www.cnblogs.com/Al-Ca/p/11222899.html
Copyright © 2020-2023  润新知