HDU 5136 Yue Fei's Battle

来源:互联网 发布:协议数据单元包两部分 编辑:程序博客网 时间:2024/04/30 05:48

题目大意:求最长链为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;}



0 0
原创粉丝点击