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

8 篇文章 0 订阅

题目

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

分析

这里写图片描述
我们找一找每层黑点和白点的规律

层数白点数黑点数
110
201
311
412
523
……

又发现一棵以白点为根的子树和原树结构一样,
一棵以黑点为根的子树和从第二层开始原树结构一样,
预处理出每层黑白点的个数,个数前缀和以及每层黑白点的个数,个数前缀和。
那么假设神奇点对的lca为白点,那么lca一定是点对中的一个点(观察结构得出),
枚举距离为i,那么个数就是一颗以白点为根的子树第i+1层的白点个数,乘以有多少个这样的子树。
同样,假设神奇点对的lca为黑点,
枚举两个点到达lca的距离分别为i和j,那么个数就是一颗以黑点为根的子树第i+1层的白点个数,乘以一颗以黑点为根的子树第i+1层的白点个数,乘以有多少个这样的子树。

#include <cmath>
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <queue>
const int maxlongint=2147483647;
const long long mo=123456789;
const int N=5005;
using namespace std;
long long w[N],sum[N],n,ans[N*2],b[N],sum1[N];
int main()
{
    scanf("%lld",&n);
    w[1]=1;
    w[2]=0;
    w[3]=1;
    for(int i=4;i<=n;i++) w[i]=(w[i-1]+w[i-2])%mo;
    for(int i=1;i<=n;i++) sum[i]=(sum[i-1]+w[i])%mo;
    b[1]=0;
    b[2]=1;
    for(int i=3;i<=n;i++) b[i]=(b[i-1]+b[i-2])%mo;
    for(int i=1;i<=n;i++) sum1[i]=(sum1[i-1]+b[i])%mo;
    for(int i=1;i<=n;i++) 
        ans[i]=sum[n-i]*w[i+1]%mo;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
        {
            ans[i+j]=(ans[i+j]+sum1[n-max(i,j)]*w[i]%mo*w[j+1]%mo)%mo;
        }
    for(int i=1;i<=n*2;i++) printf("%lld ",ans[i]);
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值