zoukankan      html  css  js  c++  java
  • Prufer 序列

    tip:

      Prufer 序列将一棵树表示成了一个长度为 节点数 -2 的序列,且每个 Prufer 序列对应且只对应一棵树。

    性质:

      1、每个节点在 Prufer 序列中出现的次数就是 这个节点的度数 -1。

      2、n 个点构成的无根树的个数: $n^{n-2}$

      3、确定 n 个点度数分别为 d1,d2 … 时无根树个数:$(n-2)!/((d1-1)!*(d2-1)!…)$

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

    实战:

    T1:明明的烦恼

    题干:

      自从明明学了树的结构,就对奇怪的树产生了兴趣 ...... 给出标号为 1 到 N 的点,以及某些点最终的度数,允许在任意两点间连线,可产生多少棵度数满足要求的树?
      输入第一行为 N(0<N<=1000),接下来N行,第 i+1 行给出第i个节点的度数 Di ,如果对度数不要求,则输入 -1。
      输出一个整数,表示不同的满足要求的树的个数,无解输出 0

    题解:

      这道题只给了一部分点的度数,无法直接用上面的性质,但可以稍变一下式。

      当我们 n 个节点度数全部可知,解就为:

    $frac{(n-2)!}{prod_{i=1}^n(d_i-1)!}$

      但我们并没有全部知道,设已知序列长度为 $sum$ ,则有:

    $sum=sum_{i=1}^n{d_i-1}$

      设我们知道的节点数为 $cnt$,则有:

      $C_{n-2}^{sum}frac{sum!}{prod_{i=1}^n(d_i-1)!}$

      我们还剩下 $n-cnt$ 个未知的:

    $C_{n-2}^{sum}frac{sum!}{prod_{i=1}^n(d_i-1)!} imes (n-cnt)^{n-2-sum}$

      化简可得:

    $frac{(n-2)!}{(n-2-sum)!prod_{i=1}^n(d_i-1)!} imes (n-cnt)^{n-2-sum}$

      最后打一个线筛,唯一分解就可以了。

    Code:

     1 #include<cstdio>
     2 #include<cstring>
     3 #define ll long long
     4 #define $ 2100
     5 using namespace std;
     6 int m,n,k,t,c[$],maxx,lst[$],prime[$],cnt,sum,tot,a[$];
     7 bool judge[$],vis;
     8 inline int max(int x,int y){    return x>y?x:y;    }
     9 inline void cut(int x,int add){
    10     if(x<1) return ;
    11     while(x!=1) maxx=max(maxx,lst[x]), c[lst[x]]+=add, x/=lst[x];
    12 }
    13 inline void eular(){
    14     lst[1]=1;
    15     for(register int i=2;i<=n;++i){    
    16         if(!judge[i]) lst[i]=i, prime[++cnt]=i;
    17         for(register int j=1;j<=cnt&&i*prime[j]<=n;++j){
    18             judge[i*prime[j]]=1, lst[i*prime[j]]=prime[j];
    19             if(i%prime[j]==0) break;
    20         }
    21     }
    22 }
    23 signed main(){
    24     scanf("%d",&n); eular();
    25     for(register int i=2;i<=n-2;++i) cut(i,1);
    26     for(register int i=1,x;i<=n;++i){
    27         scanf("%d",&x);
    28         if(x!=-1){
    29             tot++, sum+=x-1;
    30             for(register int j=2;j<=x-1;++j) cut(j,-1);
    31         }
    32     }
    33     if(n-2-sum<0){    puts("0"); return 0;    }
    34     for(register int i=2;i<=n-2-sum;++i) cut(i,-1);
    35     for(register int i=1;i<=n-2-sum;++i) cut(n-tot,1);
    36     a[0]=a[1]=1;
    37     ll yu=0;
    38     for(register int i=2;i<=maxx;++i){
    39         if(c[i]<0){    puts("0"); return 0;    }
    40         for(register int j=1;j<=c[i];++j){
    41             for(register int k=1;k<=a[0];++k){
    42                 a[k]=a[k]*i+yu;
    43                 yu=a[k]/10; a[k]%=10;
    44             }
    45             while(yu) a[++a[0]]=yu%10, yu/=10;
    46         }
    47     }
    48     for(register int i=a[0];i;--i) printf("%d",a[i]);
    49 }
    View Code
    越努力 越幸运
  • 相关阅读:
    .NET的SqlHelper应用代码
    .NET获取客户端的操作系统、IP地址、浏览器版本
    Codevs 3981 动态最大子段和
    洛谷 P3373 【模板】线段树 2
    一些笔记【杂】
    洛谷 P1432 倒水问题
    洛谷 P2324 [SCOI2005]骑士精神
    Codevs 1010 过河卒
    POJ 3278 Catch That Cow
    洛谷P2184 贪婪大陆
  • 原文地址:https://www.cnblogs.com/OI-zzyy/p/11235584.html
Copyright © 2011-2022 走看看