数格子 状压DP 矩阵优化

模拟赛  T2

乍一看题似乎是poj2411简化版   (poj2411)。

然而一看数据范围就懵了,10^9,只能用矩阵快速幂优化了。

为方便,把这个图设为N行4列。

二进制数位上的1表示这一列的这一块是一个竖着的1*2骨牌的上面一半。

状态 i 能转移到 j,当且仅当 i & j ==0 (这样1一定对应0,表示补全竖着的1*2骨牌),且 i | j 的二进制表示中每一段连续的0都有偶数个(表示横着放的骨牌,不能是奇数个)。(借鉴了李煜东学长的书☺

若状态 i 能转移到 j ,则把邻接矩阵的a[i][j]赋值为1 。

前几天讲图论时提到邻接矩阵 a^k 中的每一个元素表示 i 到 j 恰走 k 条路的方案数。

这里同理,就是从最开始什么都没有放到最后都放完(也相当于什么都没有)恰放N行的方案数。

所以这样就完了~

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#define ll long long
using namespace std;
ll n,m,ans;
struct Matrix{
	ll a[20][20];
	void init()
	{
		memset(a,0,sizeof a);
		for(int i=0;i<16;i++) a[i][i]=1;
	}	
}lj;
Matrix mul(Matrix x,Matrix y)
{
	Matrix z;
	memset(z.a,0,sizeof z.a);
	for(int i=0;i<16;i++)
		for(int j=0;j<16;j++)
			for(int k=0;k<16;k++)
			z.a[i][j]=(z.a[i][j]+(x.a[i][k]*y.a[k][j])%m)%m;
	return z;
}
Matrix ksm(Matrix x,ll y)
{
	Matrix ans;
	ans.init();
	while(y)
	{
		if(y&1) ans=mul(ans,x);
		x=mul(x,x);
		y>>=1;
	}
	return ans;
}
bool judge(int x)
{
	if(x==0||x==3||x==9||x==12||x==15) return 1;
	return 0;
}
void pre()
{
	for(int i=0;i<16;i++)
		for(int j=0;j<16;j++)
			if(!(i&j)&&judge(i|j)) lj.a[i][j]=1;
}
int main()
{
	freopen("count.in","r",stdin);
	freopen("count.out","w",stdout);
	pre();
	while(1)
	{
		scanf("%lld%lld",&n,&m);
		if(n==0&&m==0) break;
		Matrix x=ksm(lj,n);
		ans=x.a[0][0];
		printf("%lld\n",ans);
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值