洛谷P1896题解

# P1896

分析

首先,题目意思总结,放的位置不相邻并且左移右移后与下一层 \(and\)!\(=1\)
第一步预处理出所有在同一行中不相邻的方案数记为meiju[]
其次定义 \(dp\) 数组,\(f[i][j][k]\) 即在第 \(i\) 行,状态为 \(j\) ,国王数为 \(k\) 的方案数
\(sum_ep(j)\) 在进行预处理 \(meiju\) 时同时预处理出每种可行方案的国王 \(k\) 值用 \(num\) 数组来储存每种状态的国王数
\(pd\)\(int\) \(x\)\(int\) \(k\))判断左移右移后是否合法
三重循环,一层行数,二层状态,三层状态,判断两层状态是否合法,若合法进行下一步循环,循环国王数m
状态转移方程:\(f[i][j][num[j]+z]\)+=\(f[i-1][k][z]\)
最后 \(ans\) += \(f[n][i][m]\)(加上所有状态下的值,如果状态不合法就是 \(0\) 。可以不用考虑)

code

/*
work by Simon
*/
#include<bits/stdc++.h>
#define maxn 10
#define MAXN 1<<10
using namespace std;
int n,m,cnt;
long long ans;
int meiju[MAXN],num[MAXN];
long long f[maxn][MAXN][maxn*maxn];//不开long long 见祖宗!!! 
bool pd(int x,int y)
{
	if(!(x&y)&&(!(x&(y<<1)))&&(!(x&(y>>1))))
		return true;
	return false;
 } 
int sum_ep(int i)
{
	int res=0;
	while(i)
	{
		if(i&1)res++;
		i>>=1;
	}
	num[cnt]=res;
	return res;
 } 
int main()
{
	std::ios::sync_with_stdio(0);
	cin.tie(0);cout.tie(0);
	cin>>n>>m;
	int MAX=(1<<n);
	for(int i=0;i<MAX;i++)
		if(!(i&(i<<1))&&(!(i&(i>>1))))meiju[++cnt]=i,f[1][cnt][sum_ep(i)]=1;//
	for(int i=2;i<=n;i++)//预处理meiju数组时已经将第1行的所有情况统计下来了 ,此时从2开始 
		for(int j=1;j<=cnt;j++)
		{
			int x=meiju[j];
			for(int k=1;k<=cnt;k++)
			{
			int y=meiju[k];
			if(pd(x,y))
				for(int z=0;z<=m;z++)f[i][j][num[j]+z]+=f[i-1][k][z];
			}
		}
	for(int i=1;i<=cnt;i++)ans+=f[n][i][m];
	cout<<ans;
	return 0;
}
posted @ 2021-11-14 21:44  Simon_...sun  阅读(65)  评论(0)    收藏  举报