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
2
31
Sample Output
3
343812777493853
343812777493853
根据欧拉定理,有$a^{n}modp=a^{nmodvarphi(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 ",T.v[1][0]); } }