• Jzoj3805 小X的二叉堆计数


    题意:给你n个不同的数问你能构成多少个不同的二叉堆

    显然不能枚举,我们考虑用递推

    我们令f[i]表示以i为根的二叉堆有多少种

    令l,r为i的左右儿子,令size[i]为以i为根的堆的大小

    那么显然,f[i]=f[l]*f[r]*C(size[i]-1,size[l]),因为n个数互不相同,所以没有重复

    相当于是1~size[i]这几个数填进这个堆中,那么显然根只能填最大那个,让后在剩下的数选择size[l]个即可

    因为堆有两种,大根堆和小根堆,所以答案要乘2

    #include<stdio.h>
    #define M 1000000007
    #define L long long
    #define N 5000010
    L inv[N],js[N],f[N];
    int n,sz[N];
    inline L C(int n,int m){
    	return js[n]*inv[n-m]%M*inv[m]%M;
    }
    inline L pow(L x,int k){
    	L S=1;
    	for(;k;x=x*x%M,k>>=1)
    		if(k&1) S=S*x%M;
    	return S;
    }
    int main(){
    	scanf("%d",&n);
    	*js=*inv=1;
    	for(int i=1;i<=n;++i) {
    		js[i]=js[i-1]*i%M;
    		inv[i]=pow(js[i],M-2);
    	}
    	for(int i=n;i;--i){
    		sz[i>>1]+=++sz[i];
    		L l=(i<<1)>n?1:f[i<<1];
    		L r=(i<<1|1)>n?1:f[i<<1|1];
    		L p=(i<<1)>n?0:sz[i<<1];
    		f[i]=l*r%M*C(sz[i]-1,p)%M;
    		if(!f[i]) ++f[i];
    	}
    	if(n==1) { return 0&puts("1"); }
    	else printf("%d",(f[1]<<1)%M);
    }


  • 相关阅读:
    jedis scan实现keys功能
    java简单实现一个阻塞式线程池
    Swift运算符
    数组的使用(1)
    Linux 常用命令
    Task02:基础查询与排序
    Task01:初识数据库
    摩尔投票法
    面向对象暑期课程总结
    xpath+requests+peewee——CSDN论坛全方位爬虫
  • 原文地址:https://www.cnblogs.com/Extended-Ash/p/7774402.html
Copyright © 2020-2023  润新知