• prufer序列学习笔记


    prufer序列学习笔记

    定义

    构造方法:每次删掉一个叶节点,将其父节点加入序列中。一共删n-2次,这样可以保证不重复。

    性质

    1. prufer序列与无根树一一对应
    2. 度数为(d_i)的节点在序列中出现(d_i-1)
    3. n个节点完全图的生成树个数为(n^{n-2})
    4. 对于一颗无根树,度数序列给出,生成树个数为(frac{(n-2)!}{prod(d_i-1)!})

    例题

    HNOI2004 树的计数

    裸题。高精很恶心QAQ

    n=(int)(input())
    if n==1:
        x=(int)(input());
        if x==0:print(1);
        else:print(0);
        exit();
    g=[0 for i in range(n+200)];
    g[0]=1;
    for i in range(1,n):g[i]=g[i-1]*i;
    ans=g[n-2];tot=0;s=input().split();
    for i in range(n):
        x=(int)(s[i]);
        if x==0:print(0);exit();
        tot+=x-1;ans//=g[x-1];
    if(tot==n-2):print(ans);
    else:print(0);
    

    HNOI2008 明明的烦恼

    同样是裸题。把没有d的分配一下然后组合数算一下就好了。不想写高精度。

    BZOJ4766

    完全二分图的生成树计数

    考虑构造prufer序列的方法,删掉某个点后加入与其相连的父节点,则加入的点一定在二分图的另一边。那么考虑删去了那些点,显然最后留下来的是两个相连的点,即两边各一,则左边删除n-1个,右边删除m-1个,prufer序列里添加数量的相反。

    最开始我以为方案数是(n^{m-1}m^{n-1}{n+m-2choose {n-1}}),其实不然。发现删除一定是有顺序的,即左边-右边这样重复删。

    还有一种方法是直接上矩阵生成树定理,手算一下/找规律。

    #include<bits/stdc++.h>
    using namespace std;
    #define ll long long
    ll read(){
    	ll x=0,pos=1;char ch=getchar();
    	for(;!isdigit(ch);ch=getchar()) if(ch=='-') pos=0;
    	for(;isdigit(ch);ch=getchar()) x=(x<<1)+(x<<3)+ch-'0';
    	return pos?x:-x;
    } 
    ll n,m,p;
    ll mul(ll a,ll b){
    	ll res=0;
    	while(b){
    		if(b&1) res=(res+a)%p;
    		a=a*2ll%p;b>>=1;
    	}
    	return res;
    }
    ll ksm(ll a,ll b){
    	ll res=1;
    	while(b){
    		if(b&1) res=mul(res,a);
    		a=mul(a,a);b>>=1;
    	}
    	return res;
    }
    int main(){
    	n=read(),m=read(),p=read();
    	printf("%lld",mul(ksm(n,m-1),ksm(m,n-1)));
    	return 0;
    }
    
  • 相关阅读:
    java实现复制网站内容
    java实现复制网站内容
    java实现递归连续数
    java实现递归连续数
    java实现递归连续数
    java实现递归连续数
    java实现递归连续数
    java实现串中找数字
    java实现串中找数字
    java实现串中找数字
  • 原文地址:https://www.cnblogs.com/lcyfrog/p/12835675.html
Copyright © 2020-2023  润新知