首页 > 代码库 > hdu 5136(dp计数)

hdu 5136(dp计数)

题目链接


题意:直径为K的每个点的边数不超过3的相互不同构的树有多少种?


解法:把树的直径拉开,两边就是两棵二叉树了。子问题:一个深度为m的不同构的二叉树有多少种?dp[i]表示深度为i的个数。sum[i]表示dp的前缀和。转移方程就是:dp[i+1]=dp[i]*sum[i-1]+dp[i]+dp[i]*(dp[i]-1)/2;

然后回到原问题:如果K是偶数(想象中间有个虚拟的不动点),则两边是两棵深度为K/2的二叉树,答案为:dp[i]*(dp[i]-1)/2+dp[i]

如果K为奇数,则中间还有一个节点:他也是颗二叉树,则分两种大情况:

                               第三个二叉树的深度小于K/2,则sum[K/2-1]*(dp[K/2]*(dp[K/2]-1)/2+dp[K/2])即可;

                               第三个二叉树的深度等于K/2,则分三类讨论:1 三棵二叉树结构一样dp[K/2] 2 两棵一样,2 另一棵不一样:dp[K/2]*(dp[K/2]-1) 3 三棵都不一样:dp[K/2]*(dp[K/2]-1)*(dp[K/2]-2)/6


代码:

/******************************************************
* @author:xiefubao
*******************************************************/
#pragma comment(linker, "/STACK:102400000,102400000")
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <queue>
#include <vector>
#include <algorithm>
#include <cmath>
#include <map>
#include <set>
#include <stack>
#include <string.h>
//freopen ("in.txt" , "r" , stdin);
using namespace std;

#define eps 1e-8
#define zero(_) (abs(_)<=eps)
const double pi=acos(-1.0);
typedef long long LL;
const int Max=100010;
const LL INF=1000000007;
LL ans[Max];
LL sum[Max];
LL powa(LL t,LL p)
{
    LL ans=1;
    while(p)
    {
        if(p&1)
            ans=(ans*t)%INF;
        t=(t*t)%INF;
        p>>=1;
    }
    return ans;
}
LL getreverse(LL t)
{
    return powa(t,INF-2)%INF;
}
LL getans(int t)
{
    int l=t/2;
    LL rem=((ans[l]*((ans[l]-1+INF)%INF)%INF*getreverse((LL)2))%INF+ans[l])%INF;
    //cout<<ans[l]<<" "<<rem<<endl;
    if(t&1)
    {
        rem=(rem*sum[l-1])%INF;
        rem=(rem+ans[l])%INF;
        rem=(rem+ans[l]*(ans[l]-1)%INF)%INF;
        rem=(rem+ans[l]*((ans[l]-1+INF)%INF)%INF*((ans[l]-2+INF)%INF)%INF*getreverse(6)%INF)%INF;
        return rem;
    }
    else
    {
        return rem;
    }
}
LL geter(int t)
{
    return (ans[t-1]*sum[t-2]%INF+ans[t-1]*((ans[t-1]-1+INF)%INF)%INF*getreverse(2)%INF+ans[t-1])%INF;
}
void init()
{
    ans[0]=1;
    ans[1]=1;
    ans[2]=2;
    sum[0]=1;
    sum[1]=2;
    sum[2]=4;

    for(int i=3; i<Max; i++)
    {
        ans[i]=geter(i);
        sum[i]=(sum[i-1]+ans[i])%INF;
    }

}
int main()
{
    init();
    int n;
    while(cin>>n&&n)
    {
        cout<<getans(n)<<endl;
    }
    return 0;
}


hdu 5136(dp计数)