拼图(矩阵快速幂)

来源:互联网 发布:厦门理工软件学院地址 编辑:程序博客网 时间:2024/05/16 14:15



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








0 0
原创粉丝点击