1. 程式人生 > >BZOJ_5118_Fib數列2_矩陣乘法+歐拉定理

BZOJ_5118_Fib數列2_矩陣乘法+歐拉定理

-s names () 接下來 ret ++ algo urn AI

BZOJ_5118_Fib數列2_矩陣乘法+歐拉定理

Description

Fib定義為Fib(0)=0,Fib(1)=1,對於n≥2,Fib(n)=Fib(n-1)+Fib(n-2) 現給出N,求Fib(2^n).

Input

本題有多組數據。第一行一個整數T,表示數據組數。 接下來T行每行一個整數N,含義如題目所示。 n≤10^15, T≤5

Output

輸出共T行,每行一個整數為所求答案。 由於答案可能過大,請將答案mod 1125899839733759後輸出

Sample Input

2
2
31

Sample Output

3
343812777493853

根據歐拉定理,有$a^{n}modp=a^{nmod\varphi(p)}modp$。 然後矩陣乘法即可。需要用到快速乘 代碼:
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
typedef long long ll;
const ll p=1125899839733759ll;
ll n;
ll qc(ll x,ll y,ll mod) {
    ll re=0;
    for(;y;y>>=1ll,x=(x+x)%mod) if(y&1ll) re=(re+x)%mod;
    return re;
}
ll qp(ll x,ll y,ll mod) {
    ll re=1;
    for(;y;y>>=1ll,x=qc(x,x,mod)) if(y&1ll) re=qc(re,x,mod);
    return re;
}
struct Mat {
    ll v[2][2];
    Mat() {memset(v,0,sizeof(v));}
    Mat operator * (const Mat &x) const {
        Mat re; int i,j,k;
        for(i=0;i<2;i++) {
            for(j=0;j<2;j++) {
                for(k=0;k<2;k++) {
                    (re.v[i][j]+=qc(v[i][k],x.v[k][j],p))%=p;
                }
            }
        }
        return re;
    }
};
Mat pow(Mat &x,ll y) {
    Mat I;
    I.v[0][0]=I.v[1][1]=1;
    while(y) {
        if(y&1ll) I=I*x;
        x=x*x;
        y>>=1ll;
    }
    return I;
}
int main() {
    int T;
    scanf("%d",&T);
    while(T--) {
        scanf("%lld",&n);
        n=qp(2,n,p-1);
        Mat x;
        x.v[0][1]=x.v[1][0]=x.v[1][1]=1;
        Mat T=pow(x,n);
        printf("%lld\n",T.v[1][0]);
    }
}

BZOJ_5118_Fib數列2_矩陣乘法+歐拉定理