Description
众所周知,树是 n 个节点 n-1 条边的结构,而所谓的优美的树需要满足如下条件:
- 这是一棵有根二叉树;
- 非叶节点需有两个儿子;
- 不可以变换为 k-左偏树。
所谓的 k-左偏树是指一棵有 k 个叶子的树,每个非叶节点的右儿子均为叶子且均有左儿子。
所谓的变换指的是经过若干次如下两种变换:
- 删去一个节点的两个儿子;
- 用一个节点的某个儿子替换该节点。
如下图,若 k=3 则这不是一棵优美的树。

现在给你 k 和 n,想要你求出叶子数为 1,2,3…n 的优美的树分别有多少。
一行两个整数 k 和 n。
Output
n 行第 i 行一个正整数表示叶子数为 i 时的答案。答案很大所以对 1,000,000,009 取模。
shu.inshu.out4 51
1
2
4
87 61
1
2
5
14
42
HINT
对于 30%的数据 n,k<=500;
对于另外 40%的数据 k<=20;
对于 100%的数据 n,k<=5,000。
Solution
实际上不能有k-左偏树就是让你从根走到每个叶子经过左儿子个数<k (根算左孩子)
我们把n个叶子扒掉,剩下n-1个节点,那么我们只需从根走到每个儿子都不经过大于等于k-1个左儿子即可
考虑按照先续遍历填入n-1个点,填入i+1个点的时候:
- 将其填在i个点的左儿子 \( f_{i,j} \rightarrow f_{i+1,j+1}\)
- 将其填在i个点的右儿子 \( f_{i,j} \rightarrow f_{i+1,j}\)
- 将其填在祖先的某个节点的右儿子(因为是先序遍历,左儿子已经填过了) \( f_{i,j} \rightarrow f_{i+1,j-k},k \gt 0\)
这个dp可以后缀和优化, \( O(n^2) \) 即可通过这道题目。
巧妙之处:
- 用先序遍历,不重不漏;
- 预先去掉所有叶子,去掉每个非叶子节点有两个孩子这个限制;
- 后缀和优化。
std值得一看。。。
Code
我的。。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
| #include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <functional>
#include <map>
#include <queue>
#include <set>
//#define OJ
#define PROB "shu"
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
const int INF = 1000000009;
const int maxn = 100005;
//struct edge_T {int to, next;} edge[maxn<<1];
inline int getint() {
int r = 0; bool b = true; char c = getchar();
while ('0' > c || c > '9') {if (c == '-') b = false; c = getchar();}
while ('0' <= c && c <= '9') {r = r * 10 + (c - '0'); c = getchar();}
if (b) return r;
return -r;
}
int n, k, f[5005][5005], g[5005][5005];
int main() {
#ifndef OJ
freopen(PROB".in", "r", stdin);
freopen(PROB".out", "w", stdout);
#endif
k = getint(); n = getint();
f[1][1] = 1;
g[1][1] = 1;
for (int i = 2; i <= n; ++i) {
for (int j = 1; j < k; ++j)
f[i][j] = g[i-1][j-1];
for (int j = k-1; j >= 1; --j)
g[i][j] = (g[i][j+1] + f[i][j]) % INF;
}
for (int i = 1; i <= n; ++i) printf("%d\n", g[i][1]);
fclose(stdin);
fclose(stdout);
return 0;
}
|
std!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| #include <algorithm>
#include <cstdio>
using namespace std;
const int N=5005,Mod=1e9+9;
int k,n,f[N][N];
int main(){
freopen("shu.in","r",stdin);
freopen("shu.out","w",stdout);
scanf("%d%d",&k,&n);
f[1][1]=1;
for(int i=2;i<=n;i++)
for(int j=k-1;j;j--)
f[i][j]=(f[i][j+1]+f[i-1][j-1])%Mod;
for(int i=1;i<=n;i++) printf("%d\n", f[i][1]);
return 0;
}
|