【WC模拟】优美的树

Description

众所周知,树是n 个节点n-1 条边的结构,而所谓的优美的树需要满足如下条件:
1. 这是一棵有根二叉树;
2. 非叶节点需有两个儿子;
3. 不可以变换为k-左偏树。
所谓的k-左偏树是指一棵有k 个叶子的树,每个非叶节点的右儿子均为叶子且均有左儿子。
所谓的变换指的是经过若干次如下两种变换:
1. 删去一个节点的两个儿子;
2. 用一个节点的某个儿子替换该节点。
现在给你k 和n,想要你求出叶子数为1,2,3…n 的优美的树分别
有多少。
n,k<=5000

Solution

WC的题果然劲,推了两个小时还是没有结果。。。
正解超级机智的说~
首先我们可以发现,一棵树不可以变换为k-左偏树的条件是从根节点出发到任意一个叶子向左走的步数要小于k-1.
这样就可以Dp了,复杂度O(N^3)
那么怎么优化呢?
发现叶子很麻烦,我们每次都要保证每个非叶节点有2个儿子。
那么我们可以把所有叶子节点给扔掉!!
这样剩下的n-1个点就可以形态任意了,而且这n-1个点就可以决定这棵树的形态。
那么我们的约束就变成了从根节点出发到任意点向左走的步数要小于k-2.
我们沿着先序遍历来放节点,Fi,j表示从根节点到点i向左走了j次。
那么i+1的话我们只能放在i的儿子,或者i的某个只有左儿子的祖先的右儿子。
可以发现这些点的状态是Fi+1,0,Fi+1,1….,Fi+1,j+1
那就显然可以用前缀和优化了。
这种东西考场上谁想得到嘛~

Code

#include <cstdio>
#include <cstring>
#include <algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
const int N=5005,mo=1e9+9;
int n,k,suf[N],f[N];
int main() {
    freopen("shu.in","r",stdin);
    freopen("shu.out","w",stdout);
    scanf("%d%d",&k,&n);k-=3;
    printf("1\n");printf("1\n");
    suf[0]=1;
    fo(i,2,n-1) {
        f[0]=suf[0];
        fo(j,1,k) f[j]=suf[j-1];
        fd(j,k,0) {
            suf[j]=suf[j+1]+f[j];
            if (suf[j]>mo) suf[j]-=mo;
        }
        printf("%d\n",suf[0]);
    } 
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值