51nod 1350 斐波那契表示【斐波那契数列】

Description

每一个正整数都可以表示为若干个斐波那契数的和,一个整数可能存在多种不同的表示方法,例如:14 = 13 + 1 = 8 + 5 + 1,其中13 + 1是最短的表示(只用了2个斐波那契数)。定义F(n) = n的最短表示中的数字个数,F(14) = 2,F(100) = 3(100 = 3 + 8 + 89),F(16) = 2(16 = 8 + 8 = 13 + 3)。定义G(n) = F(1) + F(2) + F(3) + …… F(n),G(6) = 1 + 1 + 1 + 2 + 1 + 2 = 8。给出若干个数字n,求对应的G(n)。

题解

首先有一个性质:最短的表示一定是每次都取能取的最大的斐波那契数。

这样, f[i]=f[ifmax]+1(fmax) ,令 G[i] 表示 1..n f[i] 的和,显然, G[i]=g[ifmax]+ifmax+G[fmax] ,我们发现,斐波那契数很少,可以预处理,如果能够预处理出所有斐波那契数,那么,求 G[i] 就只需要 log 次递归就可以了,那么,如何来求呢?易得, G[fi]=G[fi1]+G[fifi1]+i(fifi1)1=G[fi1]+G[fi2]+ifi21

代码

#include
#include
#include
#define LL long long
#define maxn 100
using namespace std;
inline char nc(){
    static char buf[100000],*i=buf,*j=buf;
    return i==j&&(j=(i=buf)+fread(buf,1,100000,stdin),i==j)?EOF:*i++;
}
inline LL _read(){
    LL sum=0;char ch=nc();
    while(!(ch>='0'&&ch<='9'))ch=nc();
    while(ch>='0'&&ch<='9')sum=sum*10+ch-48,ch=nc();
    return sum;
}
int T,n;
LL f[maxn],g[maxn];
int find(LL x){
    int l=1,r=n;
    while(l<=r){
        int mid=(l+r)>>1;
        if(f[mid]<=x&&f[mid+1]>x)return mid;
        if(f[mid]>x)r=mid-1;
               else l=mid+1;
    }
}
LL G(LL x){
    if(!x)return 0;
    int p=find(x);
    return G(x-f[p])+g[p]+x-f[p];
}
int main(){
    freopen("fibonacci.in","r",stdin);
    freopen("fibonacci.out","w",stdout);
    T=_read();
    n=1;f[1]=f[0]=1;
    while(f[n]+f[n-1]<=1e17)f[n+1]=f[n]+f[n-1],n++;
    f[0]=0;f[n+1]=1e18;g[1]=1;g[2]=2;
    for(int i=3;i<=n;i++)g[i]=g[i-1]+g[i-2]+f[i-2]-1;
    while(T--){
        LL x=_read();
        printf("%lld\n",G(x));
    }
    return 0;
}

你可能感兴趣的:(斐波那契,51nod,数学杂题)