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

32 篇文章 0 订阅
30 篇文章 0 订阅

-##Description

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

Solution

我们设f[i]表示第i层有多少白色节点,g1[i]表示第i层有多少黑色节点,g[i]表示前i层有多少黑色节点。那么显然f[i]和g1[i]都是满足斐波那契数列的形态,所以可以线性求一下,再求一下g[i]。现在分类讨论一下。我们会发现,其实所谓求的f[i]即一个白色点往下走i步后遇到的白色节点数。i从零开始标号,n-1结尾。

1、当前白色节点与它子树的白色节点距离为i。那么显然有 f[i]nij=0f[j]

2、当存在两个白色节点的lca为黑色节点时,我们设一个白色端点到黑色端点的距离为k,那么就有ans= i1k=0f[k+1]f[ik+1]g[min(ni+k,nk)] 。但这样会出现重复情况,我们发现一个f[i]=f[i-1]+f[i-2]其实就是一个白色点由一个黑色点下方的白点和黑点转移得到,所以我们将ans= i1k=0f[k]f[ik1]g[min(ni+k,nk)] ,就没有重复情况了。

Code

#include<iostream>
#include<cmath>
#include<cstring>
#include<cstdio>
#include<algorithm>
#define ll long long
using namespace std;
const ll mo=123456789,maxn=5005,ni=61728395;
ll f[maxn],g[maxn],g1[maxn];
ll n,i,t,j,k,l,p,ans,q,z;
int main(){
    freopen("raviel.in","r",stdin);freopen("raviel.out","w",stdout);
    scanf("%lld",&n);f[0]=1;g1[1]=1;g[1]=1;
    for (i=2;i<=n;i++)
        f[i]=(f[i-1]+f[i-2])%mo,g1[i]=(g1[i-1]+g1[i-2])%mo,g[i]=(g[i-1]+g1[i])%mo;
    l=2*n;n--;
    for (i=1;i<=l;i++){
        t=0;
        for (j=0;j<=n-i;j++)
            t=(t+f[j])%mo;
        ans=t*f[i]%mo;
        if (i>n) p=n;
        else p=i;
        if (i-n>1) q=i-n;
        else q=1;
        for (k=q;k<p;k++)
            ans=(ans+f[k]*f[i-k-1]%mo*g[min(n-k,n-i+k)]%mo)%mo;
        printf("%lld ",ans);
    }   
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值