201409-5 拼图 100分 1093ms/3000ms

点击前往试题目录:https://blog.csdn.net/best335/article/details/99550556
在这里插入图片描述
思路:状态压缩+矩阵快速幂运算
解析:
----状态压缩:所要求得的拼法=第一行全部不填转移到的第二行的各种填法+由为第二行初始状态转移到第三行的各种填法…一直到由n-1行的状态转移到第n行全部填满的状态总和
----矩阵快速幂:A8=A * A * A * A * A * A * A * A = A4 * A4 ; A4=A2 * A2;
只需要O(logn * (1<<m)3)就可以把矩阵An求出来,而常规方式需要O(n * (1<<m)3)。
参考:https://blog.csdn.net/blzorro/article/details/41786121

#include<iostream>
#include<cstring>
using namespace std;
long long S[128][128];
struct Matrix{
	long long mat[128][128];
	int m,n;
	Matrix(const int&m,const int&n,const bool& init = true):m(m),n(n){
		if(init)
			for(int i=0;i<m;++i)
				for(int j=0;j<n;++j)
					mat[i][j]=i==j?1LL:0LL;
		else
			memset(mat,0,sizeof(mat));
	}
	Matrix(const int&m,const int& n,const long long mat[128][128]){
		for(int i=0;i<m;++i)
			for(int j=0;j<n;++j)
				this->mat[i][j]=mat[i][j];
		this->m=m,this->n=n;
	}
	Matrix& operator*(const Matrix&m){
		Matrix mtx(m.m,m.n,false);
		for(int i=0;i<this->m;++i)
			for(int j=0;j<m.n;++j)
				for(int k=0;k<n;++k)
					mtx.mat[i][j]=(mtx.mat[i][j]+mat[i][k]*m.mat[k][j])%1000000007LL;
		memcpy(mat,mtx.mat,sizeof(mat));
		return *this;
	}
	friend Matrix& operator^(Matrix&m,long long n){
		Matrix u(m.m,m.n);
		while(n){
			if(n&1) u=u*m;
			m=m*m;
			n>>=1;
		}
		memcpy(m.mat,u.mat,sizeof(m.mat));
		return m;
	}
};
void getStatus(const int& s,short l1,short l2,const int&k,const int&n){
	if(l1==(1<<n)-1) ++S[l2][s];
	else{
		for(int i=k;i<n;++i){
			bool b11=i>0&&(l1&(1<<(i-1)))==0,b12=(l1&(1<<i))==0,b13=b11&&b12,b21=i>0&&(l2&(1<<(i-1)))==0,b22=(l2&(1<<i))==0,b23=b21&&b22;
			short l11=i>0?l1|(1<<(i-1)):l1,l12=l1|1<<i,l13=l11|l12,l21=i>0?l2|(1<<(i-1)):l2,l22=l2|1<<i,l23=l21|l22;
			if(b13&&b21) getStatus(s,l13,l21,i+1,n);//,cout<<s<<" "<<k<<" "<<l1<<" "<<l2<<" "<<l13<<" "<<l21<<endl;//└
			if(b13&&b22) getStatus(s,l13,l22,i+1,n);//,cout<<s<<" "<<k<<" "<<l1<<" "<<l2<<" "<<l13<<" "<<l22<<endl;//┘
			if(b11&&b23) getStatus(s,l11,l23,i+1,n);//,cout<<s<<" "<<k<<" "<<l1<<" "<<l2<<" "<<l11<<" "<<l23<<endl;//┌
			if(b12&&b23) getStatus(s,l12,l23,i+1,n);//,cout<<s<<" "<<k<<" "<<l1<<" "<<l2<<" "<<l12<<" "<<l23<<endl;//┐
		}
	}
}

int main(){
	long long n,m;
	memset(S,0,sizeof(S));
	cin>>n>>m;
	for(int i=0,ni=1<<m;i<ni;++i)getStatus(i,i,0,0,m);
	Matrix D(1<<m,1<<m,S);
	cout<<(D^n).mat[(1<<m)-1][(1<<m)-1]<<endl;
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值