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;
    }
    
  • 相关阅读:
    set desktop for aliyun ubuntu
    【深度学习】paddlepaddle——基于卷积神经网络的手写字识别案例
    【深度学习】paddlepaddle基础语法
    【深度学习】TensorFlow——理解张量
    【深度学习】TensorFlow——图详解
    【深度学习】TensorFlow——变量op
    【深度学习】TensorFlow——实现线性回归案例
    【深度学习】TensorFlow——理解会话
    【深度学习】TensorFlow——初识tensorflow
    【机器学习】量化策略
  • 原文地址:https://www.cnblogs.com/a1439775520/p/12947713.html
Copyright © 2011-2022 走看看