1. 程式人生 > >ACM-ICPC 2018 焦作賽區網路預賽 L Poor God Water 矩陣快速冪

ACM-ICPC 2018 焦作賽區網路預賽 L Poor God Water 矩陣快速冪

Poor God Water

  •  1000ms
  •  65536K

God Water likes to eat meat, fish and chocolate very much, but unfortunately, the doctor tells him that some sequence of eating will make them poisonous.

Every hour, God Water will eat one kind of food among meat, fish and chocolate. If there are 3 continuous hours when he eats only one kind of food, he will be unhappy. Besides, if there are 3 continuous hours when he eats all kinds of those, with chocolate at the middle hour, it will be dangerous. Moreover, if there are 3 continuous hours when he eats meat or fish at the middle hour, with chocolate at other two hours, it will also be dangerous.

Now, you are the doctor. Can you find out how many different kinds of diet that can make God Water happy and safe during N hours? Two kinds of diet are considered the same if they share the same kind of food at the same hour. The answer may be very large, so you only need to give out the answer module 1000000007.

Input

The fist line puts an integer T that shows the number of test cases. (T≤1000)

Each of the next T lines contains an integer N that shows the number of hours. (1≤N≤10^10)

Output

For each test case, output a single line containing the answer.

樣例輸入

3
3
4
15

樣例輸出

20
46
435170

題目來源

題目大意:

可憐的神水(?)每個小時都進食,可進食魚(1)、肉(2)、巧克力(0),但是有飲食法則:

1)相鄰3個小時不能進食同種事物:000,111,222;

2)相鄰3小時3種事物都吃的話,不能在中間那個小時吃巧克力:102,201;

3)相鄰3小時中間小時吃魚或者肉的話,前一小時和後一小時不能同時吃巧克力:010,020;

問有多少種進食方案。

一開始想著式3維的,寫不出來就打消了,還是矩陣構造太弱。

固定由一些項推出一些項的多維遞推可以考慮矩陣快速冪。

以兩個位單位,推後一個,寫一寫就會發現base矩陣表示的那樣子:0~8每行分別表示(0,0)~(3,3),即前面相鄰兩位i,j,能推出下面相鄰兩位(j,k),的數目(base中是1);每層結果為矩陣中數字相加。

程式碼:

#include <cstdio>
#include <cstring>
#define LL long long

const LL maxn=1e10+10;
const int MatrxSz=9;
const int mod=1e9+7;

struct Matrix{
    LL m[MatrxSz][MatrxSz];
    void init(){memset(m,0,sizeof(m));}     //也可以建構函式初始化
    Matrix operator *(const Matrix &x)
    {
        Matrix y;
        y.init();   //注意初始化
        for(int i=0;i<MatrxSz;++i){
            for(int j=0;j<MatrxSz;++j){
                for(int k=0;k<MatrxSz;++k){
                    y.m[i][j]+=(m[i][k]*x.m[k][j])%mod;
                    y.m[i][j]%=mod;
                }
            }
        }
        return y;
    }
}ans,base;

void prework()
{
    //初始化base矩陣,根據題目設計
    base.init();    //注意清零
    base.m[3][0]=base.m[6][0]=1;
    base.m[0][1]=base.m[3][1]=1;
    base.m[0][2]=base.m[6][2]=1;
    base.m[4][3]=base.m[7][3]=1;
    base.m[1][4]=base.m[7][4]=1;
    base.m[1][5]=base.m[4][5]=base.m[7][5]=1;
    base.m[5][6]=base.m[8][6]=1;
    base.m[2][7]=base.m[5][7]=base.m[8][7]=1;
    base.m[2][8]=base.m[5][8]=1;

    ans.init();     //注意清零
    for(int i=0;i<MatrxSz;++i){     //ans初始化為單位矩陣
        ans.m[i][i]=1;
    }
}

void pow(LL n)    //快速冪
{
    while(n){
        if(n&1){    //n為奇數時,ans乘上base
            ans=ans*base;
        }
        base=base*base;     //此時n為偶數(奇數已經乘上一個),更新base
        n>>=1;   //右移1位相當於除以2//別又忘記寫=!!!
    }
}

int main()
{
    int t;

    scanf("%d",&t);
    while(t--){
        prework();
        LL n;
        scanf("%lld",&n);
        if(n<3){
            if(n==1) printf("3\n");
            else if(n==2) printf("9\n");
            continue;
        }
        pow(n-2);
        LL ret=0;
        for(int i=0;i<MatrxSz;++i){
            for(int j=0;j<MatrxSz;++j){
                ret+=ans.m[i][j];
                ret%=mod;
            }
        }
        printf("%lld\n",ret);
    }

    return 0;
}

媽的所以連續進食10億個小時真的可憐/doge