Fork me on GitHub

P1939 【模板】矩阵加速(数列)

luogu 传送门
矩阵乘法快速幂,注意记录过程量;
还有就是如果前面已经算过了,直接赋值就好了。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<string>
#include<cstring> 
#define LL long long
#define MOD 1000000007
using namespace std;
LL A[4][4]={
    0,0,0,0,
    0,1,1,0,
    0,0,0,1,
    0,1,0,0,
           };
LL ans[2][4],B[4][4],C[4][4],bak[4][4],a[109];
int T;
struct H{
    LL n;int id;
}q[109];
bool cmp(H x,H y){return x.n<y.n;}; 
void Fast_Pow(LL p)
{
    p--;
    for(int i=1;i<=3;i++) for(int j=1;j<=3;j++) B[i][j]=C[i][j]=A[i][j];
    while(p)
    {
        if(p%2)//B*C 
        {
            for(int i=1;i<=3;i++) for(int j=1;j<=3;j++) bak[i][j]=B[i][j],B[i][j]=0;
            for(int i=1;i<=3;i++)
             for(int j=1;j<=3;j++)
              for(int k=1;k<=3;k++)
               B[i][j]=(B[i][j]+bak[i][k]*C[k][j]%MOD)%MOD;
        }
        //C*C 
        for(int i=1;i<=3;i++) for(int j=1;j<=3;j++) bak[i][j]=C[i][j],C[i][j]=0;
        for(int i=1;i<=3;i++)
         for(int j=1;j<=3;j++)
          for(int k=1;k<=3;k++)
           C[i][j]=(C[i][j]+bak[i][k]*bak[k][j]%MOD)%MOD;

        p/=2;
    }
    for(int i=1;i<=3;i++) bak[1][i]=ans[1][i],ans[1][i]=0;
    ans[1][1]=(bak[1][1]*B[1][1]%MOD+bak[1][2]*B[2][1]%MOD+bak[1][3]*B[3][1]%MOD)%MOD;
    ans[1][2]=(bak[1][1]*B[1][2]%MOD+bak[1][2]*B[2][2]%MOD+bak[1][3]*B[3][2]%MOD)%MOD;
    ans[1][3]=(bak[1][1]*B[1][3]%MOD+bak[1][2]*B[2][3]%MOD+bak[1][3]*B[3][3]%MOD)%MOD; 
} 
int main()
{
    scanf("%d",&T);
    for(int i=1;i<=T;i++)
    {
        scanf("%lld",&q[i].n);
        q[i].id=i;
    }
    ans[1][1]=1,ans[1][2]=1,ans[1][3]=1;
    sort(q+1,q+T+1,cmp);
    for(int i=1;i<=T;i++)
    {
        LL n=q[i].n;
        if(n<=3&&n>=1) {a[q[i].id]=1;continue;}
        if(i==1) Fast_Pow(q[1].n-3); 
        else if(n-q[i-1].n)Fast_Pow(n-q[i-1].n);
        a[q[i].id]=ans[1][1];
    }
    for(int i=1;i<=T;i++) printf("%lld\n",a[i]);
    return 0;
}
posted @ 2017-09-24 17:48  primes  阅读(111)  评论(0)    收藏  举报