vijosP1194 Domino 状压DP+矩阵优化

我们知道邻接矩阵的k次方就是一个从i到j之间允许重复路径的条数

然后我们对于这题我们也可以向着这个方向转化

先用dfs搜索出所有的状态转移,然后把每一个状态当成一个点,就变成上面的问题了

当然最极端的方法自然是推递推公式或者通项公式啦

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#include<bitset>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define down(i,a,b) for(int i=a;u>=b;i--)
using namespace std;
#define N 32
int n,m,nm,inf;
struct matrix
{
	int a[N][N];
	void clear()
	{
		memset(a,0,sizeof(a));
	}
	void OUT()
	{
		fo(i,0,m)
		{
			fo(j,0,m)
			{
				cout<<a[i][j]<<' ';
			}cout<<endl;
		}cout<<endl;
	}
	matrix operator*(const matrix b)const
	{
		matrix anss;
		fo(i,0,m)
		fo(j,0,m)
		{
			anss.a[i][j]=0;
			fo(k,0,m)
			{
				anss.a[i][j]+=a[i][k]*b.a[k][j];
				anss.a[i][j]%=inf;
			}
		}
		return anss;
	}
}I,A;
void getI()
{
	fo(i,0,m)
	fo(j,0,m)
	if(i==j)I.a[i][j]=1;
	else I.a[i][j]=0;
}

bitset<100>a;
bitset<100>pre;
void dfs(int k,unsigned long cnt,unsigned long now)
{
//	cout<<k<<' '<<pre<<' '<<a<<endl;
	if(k>nm)return;
	A.a[cnt][now]=1;
	if(!a[k-1]&&!a[k])
	{
		a[k]=1,a[k-1]=1;
		dfs(k+1,cnt,a.to_ulong());
		a[k]=0,a[k-1]=0;
	}
	dfs(k+1,cnt,now);
}

matrix KSM(matrix a,int k)
{
	matrix ret=I;
	while(k)
	{
		if(k&1)ret=a*ret;
		a=a*a;
		k>>=1;
	}
	return ret;
}

int main()
{
	scanf("%d%d%d",&n,&nm,&inf);
	m=(1<<nm)-1;A.clear();getI();
	fo(i,0,m)
	{
		a.reset();pre=i;a=m-i;
		dfs(1,i,m-i);
	}
//	A.OUT();
	matrix ans=KSM(A,n);
	cout<<ans.a[m][m]<<endl;
	return 0;
}


你可能感兴趣的:(vijosP1194 Domino 状压DP+矩阵优化)