BZOJ2734: [HNOI2012]集合选数|状压DP

这题状压DP比较神奇

对于n以内任意和6互质的数x

可以构造一个矩阵

x  3x  9x  27x....

2x  6x  18x  54x...

4x  12x   36x  108x...

......

然后发现相邻的数不能一起选

只要枚举一下所有的x就ok了

卧槽这不是经典的状压dp然后就sohehe了

#include<bits/stdc++.h>
#define M 1000000001
using namespace std;
int f[2][4444],n;
bool use[4444];
long long ans=1;
int state_compression_dp(int now)
{
	int lst=0,re=0,i,j,tmp,s1,s2;
	memset(f,0,sizeof f);
	f[1][0]=1;
	for(i=0; now*(1<<i)<=n; i++)
	{
		memset(f+(i&1),0,sizeof(f)>>1);
		for(j=0,tmp=1; now*(1<<i)*tmp<=n; j++,tmp*=3);
		for(s1=0; s1<1<<lst; s1++)
		    if(use[s1])
		        for(s2=0; s2<1<<j; s2++)
		            if(use[s2])
		                if((s1&s2)==0)
		                    f[i&1][s2]+=f[~i&1][s1],f[i&1][s2]%=M;
		lst=j;
	}
	for(j=0; j<1<<lst; j++)  re+=f[~i&1][j],re%=M;
	return re;
}
int main()
{
	scanf("%d",&n);
	for(int i=0,x=1<<12; i<x; i++)
	    if( !(i>>1&i) && !(i<<1&i) )
	        use[i]=1;
	for(int i=1; i<=n; i++)
	    if( i%2 && i%3 )
	        ans*=state_compression_dp(i),ans%=M;
	cout <<ans;
	return 0;
}


你可能感兴趣的:(状压dp)