Problem C: [noip2016十连测第八场]幻魔皇
Time Limit: 10 Sec Memory Limit: 512 MBSubmit: 10 Solved: 5
[ Submit][ Status][ Web Board]
Description
http://www.lydsy.com/JudgeOnline/upload/201610/test8888.rar
幻魔皇拉比艾尔很喜欢斐波那契树,他想找到神奇的节点对。所谓斐波那契树,根是一个白色节点,每个白色节点
都有一个黑色节点儿子,而每个黑色节点则有一个白色和一个黑色节点儿子。神奇的节点对则是指白色节点对。请
问对于深度为n的斐波那契树,其中距离为i的神奇节点对有多少个?拉比艾尔需要你对于1<=i<=2n的所有i都求出
答案。
Input
Output
Sample Input
5
Sample Output
0 2 3 3 1 1 0 0 0 0
HINT
题解:递推+乱搞
斐波那契树有一些非常好的性质。
deep 1 2 3 4 5
black 0 1 1 2 3
white 1 0 1 1 2
我们发现每层的黑点数满足斐波那契,每层的白点从第二层开始满足斐波那契数列。
我们分成两种情况进行讨论。
(1) 白点对的lca为其中的一个白点。我们只需要枚举距离,计算答案即可。
ans[i]=sum[n-i]*w[i+1] (sum[n-i]表示1-(n-i)层总共的白点数,这些白点都可以再向下延伸i个长度,白点下面连接的是一颗形如从第二层黑点开始的子树,所以是w[i+1]而不是w[i])
(2)白点对的lca为黑点。这样如果直接枚举两个深度的白点个数相乘是不对的,为什么?因为你所枚举的两个白点有可能在同一条路径上,这样就不合法了。所以我们考虑两条路径从lca黑点的黑白两个儿子中各取一个。
那么原本我们要求两条长度为i,j的路径合成一个i+j的路径,就变成了从黑儿子中选一条长度i-1的路径,从白儿子中选一条长度j-1的路径。他的黑儿子是一颗形如从第二层黑点开始的子树,所以个数为w[i+1],而白儿子就是从第一层直接开始的路径,也就是w[i]实际表示的是与lca黑点相距i+1的白点,所以个数是w[j].总之这块比较难想,画一画树就明白了。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define N 10003
#define p 123456789
#define LL long long
using namespace std;
LL n,m,f[N],w[N],b[N],sum[N];
LL ans[N];
int main()
{
scanf("%I64d",&n);
f[1]=1; f[2]=1;
for (int i=3;i<=5000;i++)
f[i]=(f[i-1]+f[i-2])%p;
w[1]=1; w[2]=0; w[3]=1; w[4]=1;
for (int i=5;i<=5000;i++) w[i]=(w[i-1]+w[i-2])%p;
for (int i=1;i<=5000;i++) sum[i]=(sum[i-1]+w[i])%p;
for (int i=1;i<n;i++)
ans[i]=sum[n-i]*w[i+1]%p; //找到n-i层的白点,然后向下走i层。
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)*w[i]%p*w[j+1])%p;
for (int i=1;i<=2*n;i++)
cout<<ans[i]<<" ";
cout<<endl;
}