BZOJ5118:Fib数列2(O1快速模)

题意:输入N,输出fib(2^N)%1125899839733759。(P=1125899839733759是素数)

思路:欧拉降幂,因为可以表示为矩阵乘法,2^N在幂的位置,矩阵乘法也可以降幂,所以有ans=a*base^num; num=2^N%(P-1)。

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const ll Mod=1125899839733759;
inline ll mul(ll x,ll y,ll p){
  return ((x*y-(ll)(((long double)x*y+0.5)/p)*p)%p+p)%p;
}
struct mat
{
    ll M[3][3];
    mat() { memset(M,0,sizeof(M)); }
    mat friend operator *(mat a,mat b)
    {
        mat res;
        for(int k=1;k<=2;k++)
         for(int i=1;i<=2;i++)
          for(int j=1;j<=2;j++)
           res.M[i][j]=(res.M[i][j]+mul(a.M[i][k],b.M[k][j],Mod))%Mod;
        return res;
    }
    mat friend operator ^(mat a,ll x)
    {
       mat res; res.M[1][1]=res.M[2][2]=1LL;
       while(x){
          if(x&1LL) res=res*a; a=a*a; x/=2;
       } return res;
    }
};
ll qpow(ll a,ll x,ll p){
    ll res=1; while(x){
        if(x&1LL) res=mul(res,a,p);
        a=mul(a,a,p); x/=2;
    } return res;
}
int main()
{
    int T; ll N,num;
    scanf("%d",&T);
    while(T--){
        scanf("%lld",&N);
        num=qpow(2LL,N,Mod-1);
        num--; if(num<0) num+=Mod-1;
        mat base,a;
        base.M[1][1]=base.M[1][2]=base.M[2][1]=1LL; a.M[1][1]=1LL;
        base=base^num;
        a=base*a;
        printf("%lld
",a.M[1][1]);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/hua-dong/p/9669206.html