zoukankan      html  css  js  c++  java
  • Java实现第九届蓝桥杯堆的计数

    堆的计数
    题目描述
    我们知道包含N个元素的堆可以看成是一棵包含N个节点的完全二叉树。  
    每个节点有一个权值。对于小根堆来说,父节点的权值一定小于其子节点的权值。  
    
    假设N个节点的权值分别是1~N,你能求出一共有多少种不同的小根堆吗?  
    
    例如对于N=4有如下3种:
    
        1
       / 
      2   3
     /
    4
    
        1
       / 
      3   2
     /
    4
    
        1
       / 
      2   4
     /
    3
    
    由于数量可能超过整型范围,你只需要输出结果除以1000000009的余数。  
    
    
    【输入格式】
    一个整数N。  
    对于40%的数据,1 <= N <= 1000  
    对于70%的数据,1 <= N <= 10000  
    对于100%的数据,1 <= N <= 100000
    
    【输出格式】
    一个整数表示答案。  
    
    【输入样例】
    4  
    
    【输出样例】
    3
    
    
    资源约定:
    峰值内存消耗(含虚拟机) < 256M
    CPU消耗  < 1000ms
    
    
    请严格按要求输出,不要画蛇添足地打印类似:“请您输入...” 的多余内容。
    
    所有代码放在同一个源文件中,调试通过后,拷贝提交该源码。
    不要使用package语句。不要使用jdk1.7及以上版本的特性。
    主类的名字必须是:Main,否则按无效代码处理。
    
    

    PS:
    这里附上C++代码,还望Java大佬指点
    假设d[i]是以完全二叉树i号位置为根结点的二叉子堆个数,则考虑我们现在需要把n个点放入这个完全二叉树里,显然根节点已经被确定,只能放最小的,然后假设左子树的节点个数为lsize,则我们需要从n-1个节点中选出lsize个节点放入左子树,选法一共组合数C(n-1,lsize)种,剩余的放在右子树中,所以d[i]=C(n-1,lsize)*d[i的左儿子]*d[i的右儿子];

    注意:求组合数需要用快速幂,乘法逆元的知识。以i为根节点个数可以先用动态规划算出来,s[i]=s[i的左儿子]+s[i的右儿子];

    求阶乘逆元O(nlongn),动态规划O(n);

    所以此算法的时间复杂度O(nlongn),在本题最大数据10^5下,具有时间可行性;

    #include <iostream>
    #include <cstdio>
    #define _for(i,a,b) for(int i=a;i<b;i++)
    #define _unfor(i,a,b) for(int i=a;i>=b;i--)
    #define mset(a,val,n) for(int i=0;i<n;i++)a[i]=val;
     
    using namespace std;
    typedef long long LL;
    LL d[100005],s[100005],mod=1000000009;
    LL f[100005],inv[100005],n;
    LL C(LL n,LL m){
        return f[n]*inv[m]%mod*inv[n-m]%mod;
    }
    LL qpow(LL a,LL n){
        if(!n||a==1)return 1;
        LL x=qpow(a,n/2);
        return n%2?(x*x%mod*a%mod):(x*x%mod);
    }
    int main(){
        cin>>n;
        f[0]=1;
        _for(i,1,100005){
            f[i]=f[i-1]*i%mod;
            inv[i]=qpow(f[i],mod-2);
        }
        _unfor(i,n,1)
            s[i]=(i*2<=n?s[i*2]:0)+((i*2+1)<=n?s[i*2+1]:0)+1; //c[i]<=n所以不用取余
        //初始化子树节点个数
        mset(d,1,n+5);
        _unfor(i,n,1)if(i*2+1<=n)
            d[i]= ((C(s[i]-1,s[i*2+1])*d[i*2])%mod*d[i*2+1])%mod;
        cout<< d[1]<<endl;
    }
    
  • 相关阅读:
    cf D. Vessels
    cf C. Hamburgers
    zoj 3758 Singles' Day
    zoj 3777 Problem Arrangement
    zoj 3778 Talented Chef
    hdu 5087 Revenge of LIS II
    zoj 3785 What day is that day?
    zoj 3787 Access System
    判断给定图是否存在合法拓扑排序
    树-堆结构练习——合并果子之哈夫曼树
  • 原文地址:https://www.cnblogs.com/a1439775520/p/12947714.html
Copyright © 2011-2022 走看看