[BZOJbegin][noip2016十连测第八场]幻魔皇(dp)

题目描述

传送门

题解

画一画树就可以发现,fibnacci树有一些非常有趣的性质:
①每一层的节点数、白点数和黑点数都满足fibnacci数列。
②两个白点的lca要么是其中的一个白点,要么是另外一个黑点。
③由于构造树的规则是一定的,所以每一个节点的子树都可以用根的来表示。

wh[i]表示前i层的白点个数,sum表示wh的前缀和。我们可以分情况讨论。
①两个白点的lca是其中的一个白点。可以枚举一个距离i,那么现在深度在n-i层之上的所有白点都可以向下延伸i个长度。那么每一个节点之下i层的节点数就相当于是从第一层开始向下i层,也就是wh[i+1]。
②两个白点的lca是一个黑点。那么要保证不和第一种情况冲突,就必须是从这个黑点的黑白两个儿子里各选一个点。可以枚举这两个白点到它们lca的深度,用白点数将黑点数求出来然后再乘以各自深度的那一层的白点数就可以了。和上面的相似,不过细节比较蛋疼。

代码

#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
#define LL long long
#define Mod 123456789
#define N 10005

int n;
LL wh[2*N],sum[2*N],ans[4*N];

int main()
{
    scanf("%d",&n);
    wh[1]=1;wh[2]=0;
    for (int i=3;i<=n;++i) wh[i]=(wh[i-1]+wh[i-2])%Mod;
    for (int i=1;i<=n;++i) sum[i]=(sum[i-1]+wh[i])%Mod;

    for (int i=1;i<=n;++i)
        ans[i]=(ans[i]+sum[n-i]*wh[i+1]%Mod)%Mod;
    for (int i=1;i<=n;++i)
        for (int j=1;j<=n;++j)
            ans[i+j]=(ans[i+j]+(sum[n-max(i,j)+1]-1)*wh[i+1]%Mod*wh[j]%Mod)%Mod;
    for (int i=1;i<=2*n;++i)
        printf("%lld ",ans[i]);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值