[日常训练]斐波那契数

Description

设$f(0)=0,f(1)=1,f(i)=f(i-1)+f(i-2)(i\;\geq\;2)$,求$f(f(n))\;mod\;10^9+7$。

Input

第一行一个数表示数据组数$t$。

接下来$t$行,每行包含一个正整数$n$。

Output

输出共$t$行,每行一个整数表示答案。

Sample Input

3

3

20

30

Sample Output

1
365706550
899899483

HINT

$1\;\leq\;n\;\leq\;10^100,0<t\;\leq\;10^4$.

Solution

$f(x)\;\equiv\;f(x\;mod\;2\;\times\;10^9+16)(mod\;10^9+7)$

$f(x)\;\equiv\;f(x\;mod\;329616)(mod\;2\;\times\;10^9+16)$

所以只需要先将输入$mod\;329616$求一次$f()$,然后$\;mod\;2\;\times\;10^9+16$求一次$f()$即可。

#include<cmath>
#include<ctime>
#include<queue>
#include<stack>
#include<cstdio>
#include<vector>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#define N 2
#define M1 329616ll
#define M2 2000000016ll
#define M3 1000000007ll
using namespace std;
typedef long long ll;
struct matrix{
    ll a[N][N];int n,m;
}a,b,c;
ll n;int t;
inline ll read(){
    ll ret=0ll;char c=getchar();
    while(!isdigit(c))
        c=getchar();
    while(isdigit(c)){
        ret=((ret<<1ll)+(ret<<3ll)+c-'0')%M1;
        c=getchar();
    }
    return ret;
}
inline matrix mul(matrix a,matrix b,ll p){
    matrix ret;
    ret.n=a.n;ret.m=b.m;
    for(int i=0;i<ret.n;++i)
        for(int j=0;j<ret.m;++j){
            ret.a[i][j]=0ll;
            for(int k=0;k<ret.n;++k)
                ret.a[i][j]=(ret.a[i][j]+a.a[i][k]*b.a[k][j]%p)%p;
        }
    return ret;
}
inline matrix po(matrix a,ll k,ll p){
    matrix ret;
    ret.n=ret.m=a.n;
    for(int i=0;i<ret.n;++i)
        for(int j=0;j<ret.m;++j)
            if(i!=j) ret.a[i][j]=0ll;
            else ret.a[i][j]=1ll;
    while(k){
        if(k&1ll) ret=mul(ret,a,p);
        a=mul(a,a,p);k>>=1ll;
    }
    return ret;
}
inline void Aireen(){
    a.n=2;a.m=1;a.a[0][0]=1ll;
    b.n=b.m=2;b.a[0][0]=b.a[0][1]=b.a[1][0]=1ll;
    scanf("%d",&t);
    while(t--){
        n=read();
        if(n<=1){
            printf("%lld\n",n);continue;
        }
        c=mul(po(b,n-1ll,M2),a,M2);
        if(c.a[0][0]<=1){
            printf("%lld\n",c.a[0][0]);continue;
        }
        c=mul(po(b,c.a[0][0]-1ll,M3),a,M3);
        printf("%lld\n",c.a[0][0]);
    }
}
int main(){
    freopen("fibonacci.in","r",stdin);
    freopen("fibonacci.out","w",stdout);
    Aireen();
    fclose(stdin);
    fclose(stdout);
    return 0;
}
posted @ 2017-01-03 08:34  Aireen_Ye  阅读(278)  评论(0编辑  收藏  举报
底部 顶部 留言板 归档 标签
Der Erfolg kommt nicht zu dir, du musst auf den Erfolg zugehen.