BZOJ_5118_Fib数列2_矩阵乘法+欧拉定理

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]);
    }
}

猜你喜欢

转载自www.cnblogs.com/suika/p/9062752.html