POJ_3420_Quad Tiling_搜索,矩阵快速幂,状态压缩,动态规划

探讨使用2*1方块铺满4*N方格的不同方法,并通过动态规划结合矩阵快速幂算法解决大规模数据下的计算问题。

点解码力甘弱


题意:

用2*1的方块铺满4*N的方格阵,有多少种铺法?答案模M



Input

Input consists of several test cases followed by a line containing double 0. Each test case consists of two integers, N and M, respectively.

Output

For each test case, output the answer modules M.


动态规划题目,可以从第i-1列情况推得第i列情况,但是递推需要N次,N达到10^9级别,必须用矩阵递推,用快速幂算法。

求递推矩阵折磨死我再见用搜索写,码力点解甘弱,写错一个数字查了好久,都有点想放弃了。想了想主要是一开始思路不清晰,导致写的时候总想着等会再查,但事实是深搜查错太难了,信息量太大,递归这种狗东西


代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
using namespace std;
int n;
long long mod;
const int d=(1<<4);
struct matrix{
	long long a[1<<4][1<<4];
	matrix(){memset(a,0,sizeof(a));}
	matrix operator * (const matrix& in)const{
		matrix ret;
		for(int i=0;i<d;++i)
			for(int j=0;j<d;++j)
				for(int k=0;k<d;++k){
					ret.a[i][j]+=a[i][k]*in.a[k][j];
					ret.a[i][j]%=mod;
				}
		return ret;
	}
	matrix quick_power(int n){
		if(n==1)	return *this;
		matrix tem=quick_power(n/2);
		if(n%2)	return tem*tem*(*this);
		return tem*tem;
	}
};
matrix inter,pre[5];
int num[]={0,3,6,12,15};
void dfs(int loc,int lft,int rgt){
	if(loc==8){
		++inter.a[lft][rgt];
		return;
	}
	if(loc<4){
		if(lft&(1<<loc))	dfs(loc+1,lft,rgt);
		else if(!(rgt&(1<<loc)))
			dfs(loc+1,lft,rgt|(1<<loc));
	}
	else{
		int tem=loc-4;
		dfs(loc+1,lft,rgt);
		if(tem+1<4&&!(rgt&(1<<tem))&&!(rgt&(1<<(tem+1))))
			dfs(loc+1,lft,(rgt|(1<<tem))|(1<<(tem+1)));
	}
}
void set(){
	for(int i=0;i<d;++i)
		dfs(0,i,0);
	pre[0].a[0][0]=1;
	pre[1].a[3][0]=1;
	pre[2].a[6][0]=1;
	pre[3].a[12][0]=1;
	pre[4].a[15][0]=1;
}
int main(){
	set();
	while(scanf("%d%lld",&n,&mod)!=EOF&&(n||mod)){
		if(mod==1){
			puts("0");
			continue;
		}
		if(n==1){
			puts("1");
			continue;
		}
		matrix tem=inter.quick_power(n-1);
		long long ans=0;
		for(int i=0;i<5;++i)
			ans+=(tem*pre[i]).a[d-1][0];
		printf("%lld\n",ans%mod);
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值