幻魔皇 【NOIP2017提高组模拟12.10】

Description

幻魔皇拉比艾尔很喜欢斐波那契树,他想找到神奇的节点对。
所谓斐波那契树,根是一个白色节点,每个白色节点都有一个黑色节点儿子,而每个黑色节点则有一个白色和一个黑色节点儿子。神奇的节点对则是指白色节点对。
请问对于深度为n的斐波那契树,其中距离为i的神奇节点对有多少个?拉比艾尔需要你对于1<=i<=2n的所有i都求出答案。

Input

一行一个正整数n。

Output

一行2n个整数表示答案,对123456789取模。

Sample Input

5

Sample Output

0 2 3 3 1 1 0 0 0 0

Data Constraint

对于20%的数据n<=10;
对于40%的数据n<=20;
对于60%的数据n<=30;
对于80%的数据n<=400;
对于100%的数据n<=5000。


解法

发现这张图不错
这里写图片描述
我们设根的深度为1。
则白色点每一层的个数:1,0,1,1,2,3,5……
黑色点每一层的个数:0,1,1,2,3,5……
都是斐波那契数列。
其实每一颗以白色节点为根的子树与原树是一样的。
预处理出所有的黑白点每层的个数与前缀和。
1.若神奇点对的lca是白点,那么这个lca一定是这两个点中的一个。
枚举距离为i,那么个数就是一颗以白点为根的子树第i+1层的白点个数,乘以这样子树的数量
2.若神奇点对的lca为黑点,
枚举两个点到达lca的距离分别为i和j,那么个数就是一颗以黑点为根的子树第i层的白点个数,乘以一颗以黑点为根的子树第j+1层的白点个数,乘以这样子树的数量。


代码

#include<cstdio>
#include<algorithm>
#include<cstdlib>
#include<cstring>
#include<cmath>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define ll long long

using namespace std;

const int maxn=5005;
const ll mo=123456789;
ll w[maxn],sumw[maxn],b[maxn],sumb[maxn],ans[maxn*2];
int n;

int main()
{
    freopen("raviel.in","r",stdin);
    freopen("raviel.out","w",stdout);
    scanf("%d",&n);
    w[1]=1; w[2]=0; w[3]=1;
    sumw[1]=1; sumw[2]=1; sumw[3]=2;
    fo(i,4,n) w[i]=(w[i-1]+w[i-2])%mo,sumw[i]=(sumw[i-1]+w[i])%mo;
    b[1]=0; b[2]=1; sumb[2]=1;
    fo(i,3,n) b[i]=(b[i-1]+b[i-2])%mo,sumb[i]=(sumb[i-1]+b[i])%mo;

    fo(i,1,n) ans[i]=sumw[n-i]*w[i+1]%mo;
    fo(i,1,n)
        fo(j,1,n) ans[i+j]=(ans[i+j]+sumb[n-max(i,j)]*w[i]%mo*w[j+1]%mo)%mo;
    fo(i,1,n*2) printf("%lld ",ans[i]);
}

这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值