样例解释我没看我也不知道看了能不能秒qaq,反正我不会做,我觉得还是挺厉害的呀…
先从大到小枚举fib数,不比n大就添加进集合, 得到一个fib数最大的分解,因为没有重复的数,我们用一个01串表示一个n的fib分解,如果分解出的数有这个fib数这一位就为1否则为0
假如我们写出了这样一个串 0011000101000111
感受一下就发现n的所有分解都一定是这个串里面的1拆成2个铺在左边这样弄成的
然后用归纳法可证,连着的两个11,第二个1是不能拆的,可以忽略掉他们,变成0010001010001这样
一个1向左拆,拆完一次后产生了11这样的东西,那右边那个1又是不能拆的
所以我们可以分段考虑
f[i][0/1]表示第i段有没有拆的方案数
一个简单的dp
code:
#include<set>
#include<map>
#include<deque>
#include<queue>
#include<stack>
#include<cmath>
#include<ctime>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<complex>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
const int maxn = 110;
ll n;
ll F[maxn];
int s[maxn],f[maxn];
ll g[2];
int main()
{
F[0]=F[1]=1; for(int i=2;i<=89;i++) F[i]=F[i-1]+F[i-2];
f[1]=f[2]=0; for(int i=3;i<=89;i++) f[i]=f[i-2]+1;
scanf("%lld",&n);
for(int i=89;i>=1;i--)
if(n>=F[i]) n-=F[i],s[i]=1;
if(n) return puts("0"),0;
int la=0; g[0]=0,g[1]=1;
for(int i=1;i<=89;i++) if(s[i])
{
ll g0,g1;
g0=g[1]*f[i-la]+g[0]*f[i-la+1];
g1=g[0]+g[1];
g[0]=g0;
g[1]=g1;
la=i;
}
printf("%lld\n",g[0]+g[1]);
return 0;
}