参数范围::1<=n<=10^15,1<=m<=7。
由m<7,n很大,可看出是用矩阵快速幂。复杂度O(log2(n)*2^(3m)) ~ O(10^8)可以接受。
但是,这题的建状态转移图与一般1*2的填充是不一样的,转移到另一个状态的填充方法可能不止一种。
所以这题的状态转移图不再是01矩阵。
所以还是老样子,先建立状态转移图,然后矩阵快速幂。
矩阵快速幂最好写非递归,因为m=7的时候矩阵太大了。
再给出一些测试数据:
999999999999999 7 ----------> 847356131
99999999999999 6 ----------> 917572776
924 6 -------> 584569618
2 3 ------> 2
3 7 ------> 0
4 6 ------> 18
9 5 ------> 384
30 2 ------> 1024
1 1 ------> 0
9 2 ------> 8
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#define M 1000000007
#define LL long long
using namespace std;
int K;
LL n,m;
struct Matrix{//矩阵定义
LL a[128][128];
Matrix(){for(int i=0;i<K;++i)for(int j=0;j<K;++j)a[i][j]=i==j;}
Matrix(int x){memset(a,0,sizeof(a));}
Matrix operator*(const Matrix &B)const{//矩阵乘法
Matrix C(0);
for(int i=0;i<K;++i){
for(int j=0;j<K;++j){
for(int k=0;k<K;++k){
C.a[i][j]=(C.a[i][j]+a[i][k]*B.a[k][j])%M;
}
}
}
return C;
}
Matrix power(LL k){//非递归矩阵快速幂
Matrix A(*this),R;
while(k){
if(k&1) R=R*A;
A=A*A;k>>=1;
}
return R;
}
void Show(){
for(int i=0;i<K;++i){
for(int j=0;j<K;++j){
printf("%d ",a[i][j]);
}
printf("\n");
}
}
};
Matrix A(0);
int This;
void F(int now,int next){//now表示当前行状态,next表示下一行状态
if(now+1==K){//当前行填满,表示可以到达状态next。
A.a[This][next]++;//This 到 next 的路可能不止一条
return;
}
for(int k=0;k < m;++k){
if((now>>k)&1) continue;
int temp=1 << k;
int now_,next_;
//拼上四种图案,递归
now_=temp|(temp<<1);
next_=temp;
if(k+1<m&&!(now&now_||next&next_)) F(now|now_,next|next_);
now_=temp|(temp<<1);
next_=temp<<1;
if(k+1<m&&!(now&now_||next&next_)) F(now|now_,next|next_);
now_=temp;
next_=temp|(temp<<1);
if(k+1<m&&!(now&now_||next&next_)) F(now|now_,next|next_);
now_=temp;
next_=temp|(temp>>1);
if(k&&!(now&now_||next&next_)) F(now|now_,next|next_);
break;//这里不退出的话,会导致重复
}
}
void Init(){//建立状态转移矩阵
for(This=0;This < K ;++This){
F(This,0);
}
}
int main(){
cin>>n>>m;K = 1;
for(int i=0;i<m;++i) K <<= 1;
Init();
Matrix ANS=A.power(n);
cout<<ANS.a[0][0] <<endl;
return 0;
}