51nod 1350 斐波那契表示 (找规律递推)

分析: - -! 找规律。。。首先可以归纳证明,对于n,最佳的取法是先取不大于n的最大的那个斐波那契数,然后递推.从而可以得到算出F(n)的一个方法,但是n的范围太大了,先算出n较小的情况,会发现:

第三列为F(n),第二列为G(n),可以看出第k块是由k-1块和k-2块+1合在一起得到的,从而可以先预处理前k块之和(k不会超过100),然后对于每个n,先找到最大的不超过n的那块,然后对剩下的项递归,总的复杂度为O(T*logn).

 1 #include<iostream>
 2 #include<cstring>
 3 using namespace std;
 4 typedef unsigned long long ull;
 5 ull n,len=0;
 6 ull Fibo[1000000],maxn=100000000000000005;
 7 struct _B{
 8     ull sum,len,total;
 9 }B[100];
10 void CalFibo(){
11     Fibo[0]=Fibo[1]=1;
12     Fibo[2]=2;
13     B[1].len=1;B[1].sum=1;B[1].total=1;
14     B[2].len=1;B[2].sum=1;B[2].total=2;
15     //B[3].len=2;B[3].sum=3;B[3].total=5;
16     len=3;
17     for(int i=3;;i++,len++){
18         Fibo[i]=Fibo[i-1]+Fibo[i-2];
19         //if(i==3)continue;
20         B[i].sum=B[i-1].sum+B[i-2].sum+Fibo[i-1]-Fibo[i-2];
21         B[i].len=B[i-1].len+B[i-2].len;
22         B[i].total=B[i-1].total+B[i].sum;
23         if(Fibo[i]>maxn)break;
24     }
25 }
26 ull devide(ull v,int l,int r){
27     if(r-l<=1){
28         if(Fibo[r]<=v)return r;
29         return l;
30     }
31     int t=(l+r)/2;
32     if(Fibo[t]==v)return t;
33     if(Fibo[t]>v)return devide(v,l,t);
34     return devide(v,t,r);
35 }
36 //int CalF(int k){
37 //    int cnt=0;
38 //    while(k){
39 //        k-=Fibo[devide(k,0,len)];
40 //        cnt++;
41 //    }
42 //    return cnt;
43 //}
44 ull dp(int k,ull num){
45     if(k<=0)return 0;
46     if(k<=2)return 1;
47     while(k>1&&B[k-1].len>=num)k--;
48     ull c1=B[k-1].sum;
49     ull c2=dp(k-2,num-B[k-1].len)+num-B[k-1].len;
50     return c1+c2;
51 }
52 ull solve(){
53     ull k=n,f=devide(k,0,len-1);
54     ull ans=B[f-1].total;
55     k-=Fibo[f]-1;
56     ans+=dp(f,k);
57     return ans;
58 }
59 int main(){
60     CalFibo();
61     int t;
62     cin>>t;
63 //    int g=0;
64 //    for(int i=1;i<=50;i++){
65 //        if(CalF(i)==1)cout<<endl;
66 //        cout<<i<<' '<<(g+=CalF(i))<<' '<<CalF(i)<<endl;
67 //    }
68     while(t--){
69         cin>>n;
70         cout<<solve()<<endl;
71     }
72     return 0;
73 }

 

转载于:https://www.cnblogs.com/7391-KID/p/6903311.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值