【51Nod 1379】索函数

Description

Fib[0]=0,Fib[1]=1,Fib[n]=Fib[n-1]+Fib[n-2] if n>1.
定义索函数Sor(n)=Fib[0]| Fib[1] |Fib[2]|…|Fib[n].
给定整数n,要求计算Sor(n)%1,000,000,007(1e9+7).

Solution

因为是斐波拉切数列,所以每一个二进制位至少都会有一个1,所以最后的索函数的二进制位上的所有1都是满的。
然后我们只要知道斐波拉切数列第n个的二进制位有多大。
根据公式 F(n)=(5)5((((5)+1)2)n((1(5))2)n)
我么可以用极限的思想: (1(5))2 是一个分数,当它的指数很大的时候,后面的位会趋近于0,而c++的double会忽略掉它。
所以在前90个数时候,用暴搜直接做一下就好了。
否则,用自然对数把10的底换成2的底,然后再快速幂,最后答案-1就好了。

Code

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
typedef long long ll;
const int mo=1000000007;
ll i,j,k,l,t,n,m,ans,q,wei;
double kk,lll,tt;
ll mi(ll x,ll y) {
    ll z=1;
    for(;y;y/=2,x=x*x%mo) if (y&1) z=z*x%mo;
    return z;
}
int main(){
    for(scanf("%lld",&q);q;q--){
        scanf("%lld",&n);
        if(n==1){
            printf("1\n");
            continue;
        }
        if(n<=90){
            kk=0,lll=1;
            fo(i,2,n){
                tt=kk+lll;
                kk=lll;lll=tt;
            }
            wei=0;ans=0;t=1;
            while(tt>=1){
                wei++;
                tt=tt/2;
            }
            fo(i,1,wei){
                (ans+=t)%=mo;
                (t*=2)%=mo;
            }
            printf("%lld\n",ans);
            continue;
        }
        wei=n*log((1+sqrt(5))/2)/log(2)-log(sqrt(5))/log(2);
        ans=mi(2,wei+1);
        printf("%lld\n",ans-1);
    }
}

你可能感兴趣的:(数论,斐波那契数列,自然对数,51nod,索函数)