题目描述
题解
画一画树就可以发现,fibnacci树有一些非常有趣的性质:
①每一层的节点数、白点数和黑点数都满足fibnacci数列。
②两个白点的lca要么是其中的一个白点,要么是另外一个黑点。
③由于构造树的规则是一定的,所以每一个节点的子树都可以用根的来表示。
wh[i]表示前i层的白点个数,sum表示wh的前缀和。我们可以分情况讨论。
①两个白点的lca是其中的一个白点。可以枚举一个距离i,那么现在深度在n-i层之上的所有白点都可以向下延伸i个长度。那么每一个节点之下i层的节点数就相当于是从第一层开始向下i层,也就是wh[i+1]。
②两个白点的lca是一个黑点。那么要保证不和第一种情况冲突,就必须是从这个黑点的黑白两个儿子里各选一个点。可以枚举这两个白点到它们lca的深度,用白点数将黑点数求出来然后再乘以各自深度的那一层的白点数就可以了。和上面的相似,不过细节比较蛋疼。
代码
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
#define LL long long
#define Mod 123456789
#define N 10005
int n;
LL wh[2*N],sum[2*N],ans[4*N];
int main()
{
scanf("%d",&n);
wh[1]=1;wh[2]=0;
for (int i=3;i<=n;++i) wh[i]=(wh[i-1]+wh[i-2])%Mod;
for (int i=1;i<=n;++i) sum[i]=(sum[i-1]+wh[i])%Mod;
for (int i=1;i<=n;++i)
ans[i]=(ans[i]+sum[n-i]*wh[i+1]%Mod)%Mod;
for (int i=1;i<=n;++i)
for (int j=1;j<=n;++j)
ans[i+j]=(ans[i+j]+(sum[n-max(i,j)+1]-1)*wh[i+1]%Mod*wh[j]%Mod)%Mod;
for (int i=1;i<=2*n;++i)
printf("%lld ",ans[i]);
}