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).
因为是斐波拉切数列,所以每一个二进制位至少都会有一个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就好了。
#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);
}
}