您的位置:首页 > 其它

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

2016-12-12 22:15 176 查看

Description

幻魔皇拉比艾尔很喜欢斐波那契树,他想找到神奇的节点对。

所谓斐波那契树,根是一个白色节点,每个白色节点都有一个黑色节点儿子,而每个黑色节点则有一个白色和一个黑色节点儿子。神奇的节点对则是指白色节点对。

请问对于深度为n的斐波那契树,其中距离为i的神奇节点对有多少个?拉比艾尔需要你对于1<=i<=2n的所有i都求出答案。

Solution

把一段路径拆成两段,x->lca,lca->y。

我们考虑lca的颜色。

当lca为白色的时候,那么只会有从下面到lca的路径,那么个数就是第i层白色节点的个数(找一下规律是斐波那契额数列)

当lca为黑色的时候,我们枚举左儿子的长度k,那么右儿子的长度就是i-k,然后求出这些白色节点的个数然后再乘以黑色节点的个数[枚举有儿子距离有i-k和k,那么把这个层数一下的节点加起来](也是斐波那契额数列,但是要求一下前缀和)。

但是会有一个问题,就是直接求的话,右儿子中有一些节点是左儿子里面的,那么就会算重。

所以要减去左儿子重复的情况,那么就设左儿子是白的,那么从右儿子的黑的开始,右儿子就算i-k-1深度的白节点数。

Code

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<algorithm>
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
const int maxn=10007,mo=123456789;
long long i,j,k,l,t,n,m,ans,yi,er;
long long f[maxn],a[maxn],g[maxn];
int main(){
freopen("raviel.in","r",stdin);
freopen("raviel.out","w",stdout);
scanf("%lld",&n);
f[0]=1,g[1]=1;a[1]=1;
fo(i,2,n)f[i]=(f[i-1]+f[i-2])%mo,g[i]=(g[i-1]+g[i-2])%mo,a[i]=(a[i-1]+g[i])%mo;
n--;
fo(i,1,2*n+2){
t=0;
fo(j,0,n-i)t=(t+f[j])%mo;
ans=t*f[i]%mo;
yi=(i>n)?n:i;
er=(i-n>1)?i-n:1;
fo(j,er,yi-1)ans=(ans+f[j]*f[i-j-1]%mo*a[min(n-j,n-i+j)]%mo)%mo;
printf("%lld ",ans);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: