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)中的除法应该用逆元去算
由于是要求方案数 所以就是找规律或者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; }
相关文章推荐
- 如何在UIView中使用视图控制器
- Web UI⾃动化测试平台,专治Web 的各种疑难杂症。
- MySQL 存储4个字节 java.sql.SQLException: Incorrect string value: '\...' at row 1
- UIScrollView、UITableView与UIPageController的混合用法
- Gambler's Ruin(赌徒破产问题 概率论)
- 进程间通信--popen函数和pclose函数blog.chinaunix.net/xmlrpc.php?r=blog/article&uid=25940216&id=3206312
- Android --Android Stuido混淆签名打包
- GPDB43 Administrator Guide--第七章 扩展greenplum系统
- Request中的方法调用
- Android GUI之View事件处理
- ASINetworkQueues(经典2)
- 在UILable内显示HTML页面内容
- SuiShenJi项目_登录界面
- AlertDialog.Builder
- UIScrollview UIPageViewCon troller
- UI高级第三课  音频视频——iOS学习连载31
- 张瀚荣:如何用UE4制作3D动作游戏
- Nicholas谈UE4高级渲染:动态光照迭代快
- Nicholas谈UE4对手游平台的优化和支持
- UE4手册中文翻译速查表