标签:最大 sign iostream .com ++ 最大的 情况 oid str
分析: - -! 找规律。。。首先可以归纳证明,对于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 }
标签:最大 sign iostream .com ++ 最大的 情况 oid str
原文地址:http://www.cnblogs.com/7391-KID/p/6903311.html