牛客網-2018年湘潭大學程式設計競賽:G 又見斐波那契

ITKaven發表於2018-07-26

題目傳送門

這裡需要使用矩陣快速冪(斐波那契數列的項數n一旦過大,就要考慮矩陣快速冪)。
使用矩陣快速冪的一個關鍵問題就是矩陣遞推式。
可以得到下面這個遞推式了:

遞推式
我用等式 T^(n+1)=B*T^n,來代替上面的等式
計算矩陣B得到如圖矩陣:
矩陣B

所以T^n=B^(n-1)*T
這樣直接使用矩陣快速冪計算B^(n-1),再B^(n-1)的第一行乘T的第一列,得到 A[n]
程式碼:

#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
const ll mod=1e9+7;

ll mat[][6]={
             {1, 1, 1, 1, 1, 1},
             {1, 0, 0, 0, 0, 0},
             {0, 0, 1, 3, 3, 1},
             {0, 0, 0, 1, 2, 1},
             {0, 0, 0, 0, 1, 1},
             {0, 0, 0, 0, 0, 1}
            };
ll res[6][6];
ll now[6][6];
int A[]={1, 0, 8, 4, 2, 1};

void mul(ll a[][6],ll b[][6]){

    ll c[6][6];
    memset(c,0,sizeof(c));
    for(int i=0;i<6;i++){

        for(int j=0;j<6;j++){

            if(a[i][j])
            for(int k=0;k<6;k++){

                c[i][k]=(c[i][k]+(a[i][j]*b[j][k])%mod)%mod;
            }
        }
    }
    for(int i=0;i<6;i++){

        for(int j=0;j<6;j++){

            a[i][j]=c[i][j];
        }
    }
}

void mypow(ll n){

    memset(res,0,sizeof(res));
    for(int i=0;i<6;i++) res[i][i]=1;
    for(int i=0;i<6;i++){

        for(int j=0;j<6;j++){

            now[i][j]=mat[i][j];
        }
    }
    while(n){

        if(n&1) mul(res,now);
        mul(now,now);
        n>>=1;
    }
}

int main(){

    int T;
    scanf("%d",&T);
    while(T--){

        ll n;
        scanf("%lld",&n);
        n--;
        mypow(n);
        ll sum=0;
        for(int i=0;i<6;i++){

            sum=(sum+res[0][i]*A[i])%mod;
        }
        printf("%lld\n",sum);
    }
} 

相關文章