問題描述
衣食無憂的 Q老師 有一天突發奇想,想要去感受一下勞動人民的艱苦生活。
具體工作是這樣的,有 N 塊磚排成一排染色,每一塊磚需要塗上紅、藍、綠、黃這 4 種顏色中的其中 1 種。且當這 N 塊磚中紅色和綠色的塊數均爲偶數時,染色效果最佳。
爲了使工作效率更高,Q老師 想要知道一共有多少種方案可以使染色效果最佳,你能幫幫他嗎?
Input
第一行爲 T,代表數據組數。(1 ≤ T ≤ 100)
接下來 T 行每行包括一個數字 N,代表有 N 塊磚。(1 ≤ N ≤ 1e9)
Output
輸出滿足條件的方案數,答案模 10007。
Sample input
2
1
2
Sample output
2
6
解題思路
首先我們可以發現這個題有很明顯的子結構特性,因此可以使用DP來做,但是n的數據範圍十分大。我們考慮應該用什麼優化。
設爲個格子,紅綠均爲偶數的方案數,但是這個狀態不夠,因爲當前狀態除了紅綠均爲偶數還有其他情況,我們還要添加兩個狀態。
設爲個格子,紅綠均爲奇數的方案數,爲個格子,紅綠只有一個是偶數的方案數。
我們可以列出線性轉移方程:
由於這是線性轉移方程,我們很容易想到矩陣快速冪優化,作出轉移矩陣如下:
因此可以使用矩陣快速冪優化DP來做這道題,初始狀態。
完整代碼
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <string>
#include <climits>
#include <algorithm>
#include <queue>
#include <vector>
using namespace std;
struct Matrix{
Matrix(int _size=0) {
Size=_size; mat=new int*[Size];
for (int i=0; i<Size; i++) mat[i]=new int[Size];
for (int i=0; i<Size; i++)
for (int j=0; j<Size; j++)
mat[i][j]=0;
}
Matrix(const Matrix& t){
Size=t.Size; mat=new int*[Size];
for (int i=0; i<Size; i++) mat[i]=new int[Size];
memcpy(mat,t.mat,sizeof(mat));
}
~Matrix(){
for (int i=0; i<Size; i++) delete[] mat[i];
delete[] mat;
}
Matrix operator*(const Matrix& t) const{
Matrix ret(Size);
for (int i=0; i<Size; ++i)
for (int j=0; j<Size; ++j)
for (int k=0; k<Size; ++k)
ret.mat[i][j]+=mat[i][k]*t.mat[k][j];
return ret;
}
Matrix operator%(const int m) const {
Matrix ret(Size);
for (int i=0; i<Size; i++)
for (int j=0; j<Size; j++)
ret.mat[i][j]=mat[i][j]%m;
return ret;
}
Matrix& operator=(const Matrix& t){
for (int i=0; i<Size; i++) delete[] mat[i];
delete[] mat;
Size=t.Size;
mat=new int*[Size];
for (int i=0; i<Size; i++) mat[i]=new int[Size];
for (int i=0; i<Size; i++)
for (int j=0; j<Size; j++)
mat[i][j]=t.mat[i][j];
return *this;
}
void quick_pow(int x,int m){//x次冪模m
Matrix ret(Size);
for (int i=0; i<Size; i++) ret.mat[i][i]=1;
while(x){
if(x&1) {
ret=ret*(*this); ret=ret%m;
}
*this=(*this)*(*this);
*this=(*this)%m;
x>>=1;
}
*this=ret;
}
void output(){
printf("Size: %d\n",Size);
for (int i=0; i<Size; i++){
for (int j=0; j<Size; j++)
printf("%d ",mat[i][j]);
printf("\n");
}
}
int Size;
int** mat;
};
int getint(){
int x=0,s=1; char ch=' ';
while(ch<'0' || ch>'9'){ ch=getchar(); if(ch=='-') s=-1;}
while(ch>='0' && ch<='9'){ x=x*10+ch-'0'; ch=getchar();}
return x*s;
}
int t,n;
int main(){
//ios::sync_with_stdio(false);
//cin.tie(0);
t=getint();
while(t--){
n=getint();
Matrix mat1(3);
mat1.mat[0][0]=2; mat1.mat[0][1]=0; mat1.mat[0][2]=1;
mat1.mat[1][0]=0; mat1.mat[1][1]=2; mat1.mat[1][2]=1;
mat1.mat[2][0]=2; mat1.mat[2][1]=2; mat1.mat[2][2]=2;
mat1.quick_pow(n-1,10007);
//mat1.output();
long long ans=0;
ans=mat1.mat[0][0]*2+mat1.mat[0][2]*2; ans%=10007;
printf("%lld\n",ans);
}
return 0;
}