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