[HNOI2012]集合选数

洛谷题目链接

状压$+$构造矩阵

首先,题目中要求对于每个数$x$,不能选出$2x,3x$,我们可以构造出一个矩阵,如下:

$egin{matrix}x & 3x & 9x & 27x & ...\2x & 6x & 18x & 54x & ...\4x & 12x & 36x & 108x & ...\8x & 24x & 72x & 216x & ...\... & ... & ... & ... & ...end{matrix}$

那么显然,当我们取了某个数后,例如取的是$6x$,那么我们就不能取在它右方的$18x$,以及在它下方的$12x$,对于每个矩阵中的数都如此

而在实际上,我们还要弄出一个边界,例如上面矩阵中的$216x$很可能超过$n$,所以对于每一行,我们都要弄出一个边界,所以所谓的矩阵其实是锯齿状的样子

限制条件解决了的话,就开始状压吧

代码:

#include<iostream>
#include<cstdio>
#define int long long
#define mod 1000000001
#define N 100007
using namespace std;
int n,ans=1;
int g[21][21],limit[21],vis[N],f[21][1<<12];
int Get(int x)
{
	int maxc=1,maxk=1,chang=x,kuan=x;
	while(3*chang<=n)
		++maxk,chang*=3;
	while(2*kuan<=n)
		++maxc,kuan*=2;
	g[1][1]=x;vis[x]=1;
	for(int i=2;i<=maxk;++i) g[1][i]=g[1][i-1]*3,vis[g[1][i]]=1;
	for(int i=2;i<=maxc;++i)
	{
		g[i][1]=g[i-1][1]*2;
		vis[g[i][1]]=1;
		for(int j=2;j<=maxk;++j)
		{
			if(g[i][j-1]*3>n)
				break;			
			g[i][j]=g[i][j-1]*3;
			vis[g[i][j]]=1;
		}
	}
	for(int i=1;i<=maxc;++i)
	{
		int j; 
		for(j=1;j<=maxk;++j)
			if(g[i][j])
				g[i][j]=0;
			else
				break;
		for(limit[i]=0;j<=maxk;++j)
			limit[i]|=1<<(maxk-j);
	}
	int S=(1<<maxk)-1;
	for(int i=0;i<=S;++i)
		if(!(i&(i<<1))&&!(i&(i>>1))&&!(i&limit[1]))
			f[1][i]=1;
	for(int i=2;i<=maxc;++i)
		for(int j=0;j<=S;++j)
			if(!(j&(j<<1))&&!(j&(j>>1))&&!(j&limit[i]))
			{
				f[i][j]=0;
				for(int o=0;o<=S;++o)
					if(!(o&(o<<1))&&!(o&(o>>1))&&!(o&limit[i-1])&&!(o&j))
						f[i][j]=(f[i][j]+f[i-1][o])%mod;//cout<<"sasdasd
";
			}
				
	int sum=0;
	for(int i=0;i<=S;++i)
		if(!(i&(i<<1))&&!(i&(i>>1))&&!(i&limit[maxc]))
			sum=(sum+f[maxc][i])%mod;//cout<<sum<<"
";
	
/*	printf("maxc:%d   maxk:%d
",maxc,maxk);
	for(int i=1;i<=maxc;++i)
	{
		printf("%d ",limit[i]);
	}
	printf("
");
	for(int i=1;i<=maxc;++i)
	{
		for(int j=1;j<=maxk;++j)
			printf("%d ",g[i][j]);
		printf("
");
	}*/
	return sum;
}
signed main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;++i)
		if(!vis[i])
			ans=(ans*Get(i))%mod;//printf("%d ",ans);
	printf("%d",ans);
}

  

原文地址:https://www.cnblogs.com/yexinqwq/p/10265462.html