牛客网-2018年湘潭大学程序设计竞赛:G 又见斐波那契

题目传送门

这里需要使用矩阵快速幂(斐波那契数列的项数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);
    }
} 

猜你喜欢

转载自blog.csdn.net/qq_37960603/article/details/81229046
今日推荐