参数范围::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; }