幻魔皇
(File IO): input:raviel.in output:raviel.out
Time Limits: 1000 ms Memory Limits: 524288 KB
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。
解题思路
这是一道神奇的Fibonacci题目,有一个叫Fibonacci Tree的东西,反正就是科大树,还是“嫁接的”有黑果和白果。。。
假设w[i]为第i层白果的个数,b[i]表示第i层黑果的个数,
sw[i]=∑ij=1w[j] sb[i]=∑ij=1b[j]
很明显:
- 当距离为l的两个点,x,y的lca为x,那么这样的个数为sw[n-l]*w[l+1]
- 当距离为l的两个点,x,y的lca为z,那么这样的个数为
∑i<k,i<n,k−i<nw[i]∗w[k−i+1]∗sb[n−max(i,k−i)]
codes
#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const long long maxn=123456789;
long long w[5010],b[5010],sw[5010],sb[5010];
int n;
int main()
{
freopen("raviel.in","r",stdin);
freopen("raviel.out","w",stdout);
scanf("%d",&n);
w[1]=1;
w[2]=0;
b[1]=0;
b[2]=1;
sw[1]=sw[2]=1;
sb[2]=1;
for(int i=3;i<=n;i++)w[i]=(w[i-1]+w[i-2])%maxn,b[i]=(b[i-1]+b[i-2])%maxn,sb[i]=(sb[i-1]+b[i])%maxn,sw[i]=(sw[i-1]+w[i])%maxn;
for(int k=1;k<=2*n;k++)
{
long long ans=0;
if(k<n)ans=sw[n-k]*w[k+1]%maxn;
for(int i=1;i<k;i++)
{
if(i>=n)break;
int j=k-i;
if(j>=n)continue;
ans=(ans+(w[i]*w[j+1]%maxn)*sb[n-max(i,j)]%maxn)%maxn;
}
printf("%lld ",ans);
}
}