矩阵快速幂

// luogu-judger-enable-o2
//用矩阵快速幂做斐波那契数列,通常分为4部分;
//1.初始化基准矩阵,在这代码里是b矩阵;
//2.通过斐波那契公式计算出a矩阵。
//3.进行类似快速幂的加速过程;
//4.初始答案矩阵的答案;
#include<cstdio>
#include<algorithm>
#include<string.h>
#include<math.h>
#include<queue>
using namespace std;
typedef long long ll;
const ll mod=1e9+7;
struct node{
  ll a[10][10];
}ans,A,B;
node mat(node x,node y)
{
  node c;
  for(ll i=0;i<=2;i++)
  for(ll j=0;j<=2;j++)
    c.a[i][j]=0;
  for(ll i=0;i<=2;i++)
  for(ll j=0;j<=2;j++)
  for(ll k=0;k<=2;k++)
    c.a[i][j]=(c.a[i][j]+x.a[i][k]*y.a[k][j]%mod)%mod;
  return c;
}
void quickmod(ll n)
{
  //init(); 第二步
  memset(ans.a,0,sizeof(ans.a));
  A.a[0][0]=A.a[0][2]=A.a[1][0]=A.a[2][1]=1;
  A.a[0][1]=A.a[1][1]=A.a[1][2]=A.a[2][0]=A.a[2][2]=0;

//初始化一个基本矩阵 第一步;
  for(ll i=0;i<=3;i++)
  for(ll j=0;j<=3;j++){
    if(i==j) B.a[i][j]=1;
    else B.a[i][j]=0;
  }

//第三步
  while(n){
    if(n&1) B=mat(B,A);
    A=mat(A,A);
    n>>=1;
  }
}
int main()
{
  int T;
  scanf("%d",&T);
  while(T--){
    ll n;
    scanf("%lld",&n);
    if(n<=3) printf("1\n");
    else{
      n=n-1;
      quickmod(n);

      //由上到下分别是f[3] f[2] f[1];
      //答案定在了f[1]的位置;
      ans.a[0][0]=ans.a[1][0]=ans.a[2][0]=1; //第四步;
      ans=mat(ans,B);
      printf("%lld\n",ans.a[2][0]);
    }
  }
  return 0;
}

posted @ 2019-09-09 22:35  古比  阅读(86)  评论(0编辑  收藏  举报