您的位置:首页 > 产品设计 > UI/UE

HDU 5136 Yue Fei's Battle

2015-09-23 10:41 302 查看
题目大意:求最长链为k的二叉树的方案数

由于是要求方案数 所以就是找规律或者dp 由于要mod1e9+7 所以排除了找规律 然后就尝试着用dp去做

我们先考虑树的一半的情况 先将k/2的最长链放置好 叶子处标号为1 则标号为i的点 可以另外接一个深度小于 等于i-1的子树

而dp[i]维护的是到i节点 深度为i的树的方案数 而dp[i]的前n项和则表示深度小于等于i的树的方案数 这里我们用f[i]表示dp[i]的前n项和

从dp[i-1]推到dp[i]需要考虑重复的问题 首先当i结点再接一个深度小于等于i-2 的子树时候 是不会跟dp[i-1]部分冲突的 因为dp[i-1]是深度一定为i-1的方案数

即第一部分dp[i-1]*f[i-2]

而当i结点再接一个深度等于i-1的子树的时候 这个子树的方案数也应为dp[i-1] 且2颗子树的状态一一对应

所以 其叠加后的方案数应该为C(2, dp[i-1]) (2颗子树取不同状态,因为位置可以调换 所以用C )+dp[i-1](2颗子树取相同状态)

这样 我们就得到了dp[i],而对于整棵树的方案 :

当k是偶数时,左右都为dp[k/2] 叠加后的方案数同前文推导一样 应为 C(2 , dp[k/2])+dp[k/2]

当k是奇数时,情况较为复杂,当中心节点外接一个深度严格小于k/2的子树时 只需要左右2部分dp[k/2] 去重一下 还是C(2 , dp[k/2])+dp[k/2]

当中心节点外接一个深度为k/2的子树时 这时中心节点连接了3个dp[k/2]的子树 且其状态一一对应

C(3,dp[k/2])(3颗子树取不同状态,因为位置可以调换 所以用C)+C(2,dp[k/2])*2(3颗子树取2种不同状态,但因为某一种状态是有2颗树的 所以要乘2,例(1,1,2)和(2,2,1)不同)+dp[k/2](3颗子树取相同状态)

由于存在取模运算 C(n,m)中的除法应该用逆元去算

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cctype>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<algorithm>
#include<set>
#define scnaf scanf
#define cahr char
#define bug puts("bugbugbug");
using namespace std;
typedef long long ll;
const int inf=1000000000;
const int maxn=1e5+100;
const int m=1e5;
const int mod=1e9+7;
ll dp[maxn];//深度为i的树的方案数
ll f[maxn];//深度小于等于i的树的方案数
ll inv2=500000004;
ll inv6=166666668;
void init()
{
    dp[0]=0;
    dp[1]=1;
    f[0]=1;
    f[1]=2;
    for(int i=2;i<=m;i++)
    {
        dp[i] = dp[i-1] * f[i-2] % mod + dp[i-1] * (dp[i-1] - 1 + mod) % mod * inv2 % mod;
        dp[i]=(dp[i-1]+dp[i])%mod;
        f[i]=(dp[i] + f[i-1])%mod;
    }
}
int main()
{
    init();
    int n;
    while(~scanf("%d",&n) && n)
    {
        if(n==1)
        {
            puts("1");
            continue;
        }
        ll zz=dp[n/2];
        ll ans=(zz * (zz - 1 + mod) % mod * inv2 % mod + zz)%mod;
        if(n%2)
        {
          ans = ans * f[n/2-1] % mod;
          ans =( ans+ zz * (zz-1) %mod * (zz-2) %mod * inv6 % mod +zz * (zz-1)  % mod + zz)%mod;
        }
        printf("%I64d\n",ans);
    }
    return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: