• HDU 2292


    http://acm.hdu.edu.cn/showproblem.php?pid=2292

    题意:1-n个节点,题目给出了完全二叉树的定义(这个定义似乎有歧义,此题以题目描述为准),且要保持最小堆性质(根节点小于左右子树内的任意元素),问有多少种不同组合

    解法:dp,dp[n]表示n个元素的合法排列数量。一共n个节点,左子树有a个节点,则右子树有n-1-a个节点,dp[n]=C(n-1,a)*dp[a]*dp[n-1-a],其中a可以轻易算出。

    公式解释:除去根节点,在剩下的n-1个元素中取a个,这a个元素的合法排列有dp[a]种,剩下n-1-a个节点的合法排列有dp[n-1-a]种。

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    using namespace std ;
    typedef __int64 ll ;
    ll c[1005][1005],n,m,dp[1005] ;
    ll cal(int s)
    {
        ll temp=s-1 ;
        ll cnt=2 ;
        ll ans=0 ;
        while(temp-cnt>0)
        {
            ans+=cnt/2 ;
            temp-=cnt ;
            cnt*=2 ;
        }
        if(temp>=cnt/2)ans+=cnt/2 ;
        else ans+=temp ;
        return ans ;
    }
    int main()
    {
        int t ;
        scanf("%d",&t) ;
        while(t--)
        {
            scanf("%I64d%I64d",&n,&m) ;
            memset(c,0,sizeof(c)) ;
            for(int i=1 ;i<1001 ;i++)
            {
                c[i][0]=c[i][i]=1 ;
                for(int j=1 ;j<i ;j++)
                    c[i][j]=(c[i-1][j-1]+c[i-1][j])%m ;
            }
            memset(dp,0,sizeof(dp)) ;
            dp[0]=dp[1]=1 ;
            for(int i=2 ;i<=n ;i++)
            {
                ll a=cal(i) ;
                ll b=i-1-a ;
                dp[i]=c[i-1][a]*dp[a]%m*dp[b]%m ;
            }
            printf("%I64d
    ",dp[n]%m) ;
        }
        return 0 ;
    }
    View Code
  • 相关阅读:
    XML 命名空间
    XML Schema验证
    java 解析XML文档
    Java线程:创建与启动
    CCF-CSP 201312-5 I'm stuck !
    memset函数用法
    C++的字符串多行输入
    OS复习1
    os复习2
    javamail编程2
  • 原文地址:https://www.cnblogs.com/xiaohongmao/p/3713441.html
Copyright © 2020-2023  润新知