LOJ10172涂抹果酱

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/zhangjingyanzjyer/article/details/83152053

https://loj.ac/problem/10172

题目大意就是给了你n行m列的矩阵,让你给这个矩阵的每个格子染色,有1,2,3三种颜色可以选择。同时,必须满足任意两个相邻的格子的颜色不能相同。并且第k行已经完成了染色,无法被更改。求合法的染色方案数。

这道题n的范围很大,但m的范围很小,所以很容易想到可以使用状压dp来求解。由于每一个点的状态有三种,所以要用三进制数来表示每一行的状态。处理好这一点后,就照普通的状压dp做就可以了。不过还要注意判断一下题目给出的第k行的状态是否合法,不合法就直接输出0。(其实这道题的小数据理论上是要用暴力做的,直接dp空间会炸,不过LOJ的数据没有卡这一点)

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
const long long mo=1e6;
int n,m,k,x,d[1000],d0[1000],d1[1000],num,num0,num1,sta[100035]; 
long long ans,f[100035][835];
bool check(int x)//判断该状态是否合法
{
	int cnt0=0;
	while (x)
	{
		d0[++cnt0]=x%3;
		x=x/3;
	}
	bool flag=true;
	for (int i=m;i>=2;i--)
		if (d0[i]==d0[i-1]) {flag=false;break;}
	for (int i=1;i<=cnt0;i++) d0[i]=0;
	return flag;
}
bool check0(int x,int y)//判断当前状态与上一行(或下一行)状态是否冲突
{
	int cnt0=0;
	while (x)
	{
		d0[++cnt0]=x%3;
		x=x/3;
	}
	cnt0=0;
	while (y)
	{
		d1[++cnt0]=y%3;
		y=y/3;
	}
	bool flag=true;
	for (int i=1;i<=m;i++)
		if (d0[i]==d1[i]) {flag=false;break;}
	for (int i=1;i<=m;i++){d0[i]=0;d1[i]=0;}
	return flag;
}
void ready()
{
	for (int i=0;i<d[m];i++)
	{
		if (check(i)==false || sta[1]==i) continue;
		num++;
		sta[num]=i;
	}
}
int main()
{
	scanf("%d%d",&n,&m);
	scanf("%d",&k);
	memset(d,0,sizeof(d));
	d[0]=1;
	for (int i=1;i<=m;i++)
		d[i]=d[i-1]*3;
	num=1;
	for (int i=1;i<=m;i++)
	{
		scanf("%d",&x);
		sta[1]=(sta[1]*3)+x-1;//用0,1,2三进制数来表示状态
	}
	if (!check(sta[1])) {puts("0");return 0;}
	ready();
	if (k!=2)
	{
		for (int i=1;i<=num;i++)
			f[1][sta[i]]=1;
	}
	else
	{
		for (int i=1;i<=num;i++) if (check0(sta[i],sta[1])) f[1][sta[i]]=1;
	}
	for (int i=2;i<=n;i++)
	{
		num1=num;
		if (i==k) num1=1;
		for (int j=1;j<=num1;j++)
		{
			num0=num;
			if (i-1==k) num0=1;
			for (int l=1;l<=num0;l++)
			{
				if (check0(sta[j],sta[l])==false) continue;
				if ((i==k-1) && (check0(sta[j],sta[1])==false)) continue;
				f[i][sta[j]]=(f[i][sta[j]]+f[i-1][sta[l]])%mo;
			}
		}
	}
	num0=num;
	if (n==k) num0=1; 
	for (int i=1;i<=num0;i++) ans=(ans+f[n][sta[i]])%mo;
	printf("%lld\n",ans);
}

猜你喜欢

转载自blog.csdn.net/zhangjingyanzjyer/article/details/83152053