zoukankan      html  css  js  c++  java
  • prufer序列--学习笔记

    prufer编码

    (prufer)序列可以将一个代标号的(n)个节点的树用([1,n])中的(n-2)个整数表示,可以理解为完全图的生成树与数列之间的双射。

    出自OI Wiki

    有关无根树转(prufer)编码(prufer)编码转无根树等内容可以去(OI Wiki)上看

    这里只介绍(prufer)序列的性质:

    • (prufer)序列与无根树一一对应

      相信看完了上面的链接以后您已经懂了。

    • 度数为(d_i)的节点会在(prufer)序列中出现(d_i-1)

      根据构造方法,当某个点度数为(1)时会被删掉,否则每次删掉一个相邻节点,它就会入列一次。

    • 一个(n)个节点的完全图的生成树个数为(n^{n-2})

      对于一个有(n)个节点无根树,它的(prufer)序列长为(n-2),而每个位置有(n)种可能性,所以共有(n^{n-2})种情况。

    • 对于度数为(d_{1-n})的一颗无根树共有(frac{(n-2)!}{prod_{i=1}^{n}{(d_i - 1)!}})种情况

      由性质2,度数为(d_i)的节点会在(prufer)序列中出现(d_i-1)次。所以就是(n-2)个位置选出(d_i-1)(1leq ileq n))的可重全排列了。

      可重全排列/选排列公式:

      • 可重全排列:在(n)个元素中,有(n_1)个元素彼此相同,有(n_2)个元素彼此相同……又有(n_m)个元素彼此相同,且(n_1+n_2+cdotcdotcdot+n_m=n),则这(n)个元素的全排列就是可重全排列。其公式为:(n!/(n_1! imes n_2! imes cdotcdotcdot imes n_m!))
      • 可重选排列:仍是上面拿个序列,从中选出(r)个的选排列就是可重选排列。其公式为:(A(n,r)/(n_1! imes n_2! imes cdotcdotcdot imes n_m!))

    然后就可以愉快地做题了!

    模板题Luogu2290

    利用最后一个性质即可,注意不要运算过程中爆(long;long),还有记得判无解。

    细节还是蛮多的……

    参考代码
    /*
     * @Author: When_C 
     * @Date: 2020-11-18 19:01:40 
     * @Last Modified by: When_C
     * @Last Modified time: 2020-11-18 19:29:58
     */
    #include <cstdio>
    #define LL long long
    
    using namespace std;
    
    const int maxn = 210;
    
    LL n,d[maxn],Ans,f,sum;
    
    LL gcd(LL x, LL y){
        if(!y) return x;
        return gcd(y, x % y);
    }
    
    int main(){
        scanf("%lld", &n);
        for(int i = 1; i <= n; ++ i) scanf("%lld", &d[i]);
        if(n == 1 && d[1] == 0) return printf("1
    "), 0;  //注意这个特判!!!
        Ans = f = 1; int now = 1;
        for(int i = 1; i <= n; ++ i){
            if(!d[i]) return printf("0
    "), 0;
            sum += d[i] - 1;    
            for(int j = 2; j <= d[i] - 1; ++ j){
                f *= j;
                while(Ans < f && now < n - 2) Ans *= (++now);
                LL val = gcd(Ans, f);
                Ans /= val; f /= val;
            }
        }
        if(sum != n - 2) return printf("0
    "), 0;
        while(now < n - 2){
            Ans *= (++now);
            if(Ans % f == 0 && f != -1) Ans /= f, f = -1;
        }
        if(f != -1) Ans /= f;
        printf("%lld
    ", Ans);
        return 0;
    }
    

    另一道题

  • 相关阅读:
    模块(module)
    编译和解释性语言和python运行方式
    管道通信初级
    Page.TryUpdateModel 方法
    运用模型绑定和web窗体显示和检索数据(Retrieving and displaying data with model binding and web forms)
    HttpResponse 类
    ASP.NET中IsPostBack详解
    3.4.1 使用过滤式扩展方法(P43-44)
    使用扩展方法(Chapter3 P39-41)
    C#对象初始或器-Chapter3 P38
  • 原文地址:https://www.cnblogs.com/whenc/p/14002427.html
Copyright © 2011-2022 走看看