51Nod 1350 - 斐波那契表示(找规律)

在这里插入图片描述

【思路】
先考虑如何计算 F ( n ) F(n) F(n) ,如果 n n n 是斐波那契数,那么 F ( n ) = 1 F(n)=1 F(n)=1 ,否则尽量把 n n n 减去最大可减的斐波那契数,并重复这一过程,也就是 F ( n ) = { n = 1 , n 是fib数 F ( n − m ) + 1 , n  不是fib数 F(n)=\begin{cases} n=1, & \text {$n$是fib数} \\ F(n-m)+1, & \text{$n$ 不是fib数} \end{cases} F(n)={n=1,F(nm)+1,nfibn 不是fib 根据 F ( n ) F(n) F(n) 的计算公式再来考虑计算它的前缀和 G ( n ) G(n) G(n),如果 n n n 是斐波那契数,假设 n = f i b [ i ] n=fib[i] n=fib[i],则 G ( f i b [ i ] ) − G ( f i b [ i − 1 ] ) = F ( f i b [ i − 1 ] + 1 ) + F ( f i b [ i − 1 ] + 2 ) + . . . + F ( f i b [ i ] − 1 ) + F ( f i b [ i ] ) G(fib[i])-G(fib[i-1])=F(fib[i-1]+1)+F(fib[i-1]+2)+...+F(fib[i]-1)+F(fib[i]) G(fib[i])G(fib[i1])=F(fib[i1]+1)+F(fib[i1]+2)+...+F(fib[i]1)+F(fib[i]) 根据 F F F 的计算公式,等式右端 = ( F ( 1 ) + 1 ) + ( F ( 2 ) + 1 ) + . . . + ( F ( f i b [ i ] − 1 − f i b [ i − 1 ] ) + 1 ) + F ( f i b [ i ] ) =(F(1)+1)+(F(2)+1)+...+(F(fib[i]-1-fib[i-1])+1)+F(fib[i]) =(F(1)+1)+(F(2)+1)+...+(F(fib[i]1fib[i1])+1)+F(fib[i])
= F ( 1 ) + F ( 2 ) + . . . + F ( f i b [ i ] − f i b [ i − 1 ] − 1 ) + f i b [ i ] − f i b [ i − 1 ] = G ( f i b [ i − 2 ] − 1 ) + f i b [ i − 2 ] =F(1)+F(2)+...+F(fib[i]-fib[i-1]-1)+fib[i]-fib[i-1]=G(fib[i-2]-1)+fib[i-2] =F(1)+F(2)+...+F(fib[i]fib[i1]1)+fib[i]fib[i1]=G(fib[i2]1)+fib[i2]
移项可得 G ( f i b [ i ] ) = G ( f i b [ i − 1 ] ) + G ( f i b [ i − 2 ] − 1 ) + f i b [ i − 2 ] G(fib[i])=G(fib[i-1])+G(fib[i-2]-1)+fib[i-2] G(fib[i])=G(fib[i1])+G(fib[i2]1)+fib[i2]
同理当 n n n 不是斐波那契数时,也用相同方法递推,可以得到 G ( n ) = G ( m ) + G ( n − m ) + ( n − m ) , m 是 小 于 n 的 最 大 的 f i b 数 G(n)=G(m)+G(n-m)+(n-m),m是小于n的最大的fib数 G(n)=G(m)+G(nm)+(nm),mnfib
在计算时可以提前预处理出 G ( f i b [ i ] ) G(fib[i]) G(fib[i]) 的值,直接递归计算会超时

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=90;

ll f[maxn];//fib序列 1,1,2,3,5,8,13...
ll g[maxn];//记忆化 g[i]=G(f[i]) 提高效率

ll G(ll n){
    if(n<=2) return n;
    int p=lower_bound(f,f+maxn,n)-f;
    if(f[p]==n){
        if(g[p]!=-1) return g[p];
        return g[p]=G(f[p-1])+G(f[p-2]-1)+f[p-2];
    }
    else{
        ll m=f[p-1];
        return G(m)+G(n-m)+(n-m);
    }
}

int main(){
    f[0]=f[1]=1;
    for(int i=2;i<maxn;++i) f[i]=f[i-1]+f[i-2];
    for(int i=0;i<maxn;++i) g[i]=-1;
    int T;
    scanf("%d",&T);
    while(T--){
        ll n;
        scanf("%lld",&n);
        printf("%lld\n",G(n));
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值