奶牛家谱 Cow Pedigrees

令人窒息的奶牛题

题目描述

农民约翰准备购买一群新奶牛。 在这个新的奶牛群中, 每一个母亲奶牛都生两个小奶牛。这些奶牛间的关系可以用二叉树来表示。这些二叉树总共有N个节点(3 <= N < 200)。这些二叉树有如下性质:

每一个节点的度是0或2。度是这个节点的孩子的数目。

树的高度等于K(1 < K < 100)。高度是从根到最远的那个叶子所需要经过的结点数; 叶子是指没有孩子的节点。

有多少不同的家谱结构? 如果一个家谱的树结构不同于另一个的, 那么这两个家谱就是不同的。输出可能的家谱树的个数除以9901的余数。

输入输出格式

输入格式:

两个空格分开的整数, N和K。

输出格式:

一个整数,表示可能的家谱树的个数除以9901的余数。


题目分析

无脑dfs

我们可以显而易见地想到dfs做法。给每一个点赋编号,再接着枚举有无孩子的状态。然后如果再大力剪枝,就可以惊喜地发现到$n=60$之后就TLE到飞起了。

像dp的假dp

这不是一道dp题嘛……考虑一下转移,发现每一种树要么从同一层转移过来、要么从上一层转移过来。那么接着存一存每一种树最下面一层的叶子节点数,再存一存每一种树方案总数,接着就是这些信息的转移……搞来搞去我也搞不清这是什么东西了。

树形dpⅠ

设$f[i][j]$表示$i$个节点构造出深度为$j$的树的方案数。显而易见的是,转移方程为

其中,即f[i][k]的前缀和。

在转移的时候,我们只需要枚举右孩子的节点数,再利用乘法原理乘上左孩子深度为$j-1$(除去根)的方案数。之后再将重复的情况减一下就可以了。

这看上去并没有什么问题对吧。

看到这里大佬您有没有发现这个dp出锅了呢。

是!的!这个人畜无害的dp出锅了!!!

并且截止撰写这篇博客的时候,依然没有找出问题在哪里……

如果大佬您发现了问题,麻烦在评论区留言,谢谢!

树形dp Ⅱ

XYZ表示dp方程并不用这么复杂并且表示我的代码画风清奇非常鬼畜

好吧,似乎这份是有点又臭又长的感觉

我们以$f[i][j]$表示$i$个节点,$1..j$深度的方案数的前缀和。那么转移起来就方便很多;并且得益于dp方程的定义,子树节点个数是可以枚举过去的,不存在上面做法方案数乘2的事情,因此也不用管重复的问题了。

 1 #include<bits/stdc++.h>
 2 const int MO = 9901;
 3 int f[203][203];
 4 int n,m;
 5 int main()
 6 {
 7     scanf("%d%d",&n,&m);
 8     for (int i=1; i<=m; i++)
 9         f[1][i] = 1;
10     for (int i=1; i<=n; i+=2)
11         for (int j=1; j<=m; j++)
12             for (int k=1; k<i; k+=2)
13                 (f[i][j]+=f[k][j-1]*f[i-k-1][j-1])%=MO;
14     printf("%d\n",(f[n][m]+MO-f[n][m-1])%MO);
15     return 0;
16 }

这道题真的是挺(wo)有(tai)趣(cai)的(le),这些一步一步的写法倒也是有很多值得深思的地方。

(似乎为了这题写的程序数量可以立个记录之类的?)

END

原文地址:https://www.cnblogs.com/antiquality/p/8674345.html

时间: 2024-08-26 12:38:13

奶牛家谱 Cow Pedigrees的相关文章

洛谷P1472 奶牛家谱 Cow Pedigrees

P1472 奶牛家谱 Cow Pedigrees 102通过 193提交 题目提供者该用户不存在 标签USACO 难度普及+/提高 提交  讨论  题解 最新讨论 暂时没有讨论 题目描述 农民约翰准备购买一群新奶牛. 在这个新的奶牛群中, 每一个母亲奶牛都生两个小奶牛.这些奶牛间的关系可以用二叉树来表示.这些二叉树总共有N个节点(3 <= N < 200).这些二叉树有如下性质: 每一个节点的度是0或2.度是这个节点的孩子的数目. 树的高度等于K(1 < K < 100).高度是从

[luoguP1472] 奶牛家谱 Cow Pedigrees(DP)

传送门 一个深度为i的树可以由一个根节点外加两个深度为i-1的树组成,这就决定了DP该怎么写. 然而我真的没有想到. f[i][j]表示深度为i节点数为j的个数 sum[i][j]表示深度小于等于i节点树为j的个数 #include <cstdio> #define N 402 #define p 9901 int n, m; int f[N][N], sum[N][N]; //f[i][j]表示深度为i节点数为j的个数 //sum[i][j]表示深度<=i节点数为j的树的个数 int

【luogu1472】 奶牛家谱 Cow Pedigrees [动态规划]

一时暴搜一时爽 一直暴搜一直爽  cxl居然和我写的同款dfs,天呢 菜鸡开始对这题并没有什么想法 状态方程死活想不出来 还是暴搜好 1 #include<bits/stdc++.h> 2 using namespace std; 3 #define ll long long 4 #define rg register 5 const int N=200,K=100,P=9901; 6 int n,k,f[K+5][N+5],ans=0; 7 template <class t>v

USACO 2.3 Cow Pedigrees

Cow Pedigrees Silviu Ganceanu -- 2003 Farmer John is considering purchasing a new herd of cows. In this new herd, each mother cow gives birth to two children. The relationships among the cows can easily be represented by one or more binary trees with

【USACO 2.3.2】奶牛家谱

[题目描述] 农民约翰准备购买一群新奶牛.在这个新的奶牛群中,每一个母亲奶牛都生两小奶牛.这些奶牛间的关系可以用二叉树来表示.这些二叉树总共有N个节点(3 <= N < 200).这些二叉树有如下性质: 每一个节点的度是0或2.度是这个节点的孩子的数目. 树的高度等于K(1 < K < 100).高度是从根到最远的那个叶子所需要经过的结点数;叶子是指没有孩子的节点. 有多少不同的家谱结构?如果一个家谱的树结构不同于另一个的,那么这两个家谱就是不同的.输出可能的家谱树的个数除以990

2.3.2 COW PEDIGREES 奶牛家谱

解题思路: 1.简单动态规划.基本思想是用小的二叉树去组成大的二叉树,最后输出dp[k][n]-dp[k-1][n]恰好就是要求的n个 点组成深度最多为k的方法数 2.设dp[i][j]表示j个点组成深度最多为i的二叉树的方法数,则动态规划公式为: dp[i][j]=∑(dp[i-1][l]*dp[i-1][j-1-l])(1<=l<=j-2) dp[i][1]=1 3.注意:点的个数总为奇数. 核心代码: for(i=1;i<=k;i++) dp[i][1]=1; for(i=1;i&

奶牛接力 (Cow Relays, USACO 2007 Nov)

题目描述 For their physical fitness program, N (2 ≤ N ≤ 1,000,000) cows have decided to run a relay race using the T (2 ≤ T ≤ 100) cow trails throughout the pasture. Each trail connects two different intersections (1 ≤ I1i ≤ 1,000; 1 ≤ I2i ≤ 1,000), each

Cow Pedigrees

Two possible pedigrees have 5 nodes and height equal to 3: @ @ / \ / @ @ and @ @ / \ / @ @ @ @ 题意:给你 n 个元素,可以组成多少颗深度为 m 的二叉树,每个结点的度只有 0 或 2 . 果然不好下手就是DP题.本题DP状态定义就显得十分重要了.如果直接定义dp[i][j] 表示 用i个元素 深度为j的二叉树.发现并不好转移.于是 别人就想到了 定义dp[i][j]表示 用i个元素按 深度小于等于j的

usaco Cow Pedigrees

题意是,求N,个节点,组成高度为K的二叉树,形态有多少,且每个节点的度要么为0要么为2. 这题第一眼看后就知道要dp,但却没找到方程,看了别人题解之后才知道,原来是从分治的思想出发的. dp[i][j]的意思是用i个节点组成高度不超过j的二叉树的形态,那么dp[i][j]=dp[i][j]+dp[k][j-1]*dp[i-1-k][j-1],k=1,3,5..... 就是去掉根节点之后,求出左子树节点个数为k的形态数,乘上右子树节点个数为i-1-k时的形态数. 输出dp[N][K]-dp[N][