【状压DP】BZOJ2734-[HNOI2012]集合选数
2016-08-01 16:52
344 查看
已经八月份了药丸,开始肝作业并且准备高考啦!!
【题目大意】
《集合论与图论》这门课程有一道作业题,要求同学们求出{1, 2, 3, 4, 5}的所有满足以 下条件的子集:若 x 在该子集中,则 2x 和 3x 不能在该子集中。现在求以下问题:对于任意一个正整数 n≤100000,如何求出{1, 2,..., n} 的满足上述约束条件的子集的个数(只需输出对 1,000,000,001 取模的结果)(包括空集)。
【思路】
对于n以内任意与6互质的整数x,我们列出一个矩阵:
x 3x 9x 27x ...
2x 6x 18x 54x ...
4x 12x 36x 108x ...
所以我们现在枚举与6互质的这个数x,然后进行状态压缩的转移。这个有点类似于先前的king。f[i][j]表示到第i行,且第i行状态为j的总可能性。不过它并不一定是矩形,每一行的列数可能不同,对于某行列数为j,我们只需枚举0..2^j-1的状态,并记录为before转移到下一行DP。
这里用了滚动数组,不过不要忘记每次新的滚动数组都要清空一下。
【题目大意】
《集合论与图论》这门课程有一道作业题,要求同学们求出{1, 2, 3, 4, 5}的所有满足以 下条件的子集:若 x 在该子集中,则 2x 和 3x 不能在该子集中。现在求以下问题:对于任意一个正整数 n≤100000,如何求出{1, 2,..., n} 的满足上述约束条件的子集的个数(只需输出对 1,000,000,001 取模的结果)(包括空集)。
【思路】
对于n以内任意与6互质的整数x,我们列出一个矩阵:
x 3x 9x 27x ...
2x 6x 18x 54x ...
4x 12x 36x 108x ...
所以我们现在枚举与6互质的这个数x,然后进行状态压缩的转移。这个有点类似于先前的king。f[i][j]表示到第i行,且第i行状态为j的总可能性。不过它并不一定是矩形,每一行的列数可能不同,对于某行列数为j,我们只需枚举0..2^j-1的状态,并记录为before转移到下一行DP。
这里用了滚动数组,不过不要忘记每次新的滚动数组都要清空一下。
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define mod 1000000001 using namespace std; typedef long long LL; const int MAXN=12; int n; int usable[1<<MAXN],f[2][1<<MAXN]; bool mark[1<<MAXN]; int Usable(int x) { if (x<<1&x || x>>1&x) return 0;else return 1; } int dp(int now) { memset(f,0,sizeof(f)); int cur=0,before=-1;//before指上一行有几个数 for (int i=0;now*(1<<i)<=n;i++)//枚举每一行的第一个数,求出总的行数 { cur=1-cur; int tmp=now*(1<<i),j; for (j=0;tmp<=n;j++,tmp*=3);//求出每一行有几个数 for (int k=0;k<(1<<j);k++)//枚举当前行的状态 { f[cur][k]=0;//【不要忘记了初始化☆】 if (usable[k]) { if (before==-1) {f[cur][k]=1;continue;}//如果是第一行,则将可行状态设为1 for (int p=0;p<(1<<before);p++) if (usable[p]) if ((k&p)==0) f[cur][k]=f[cur][k]+f[1-cur][p],f[cur][k]%=mod;//这里不要忘记了也要mod } } before=j; } int ans=0; for (int i=0;i<(1<<before);i++) ans+=f[cur][i],ans%=mod; return (ans); } void getusable() { memset(usable,0,sizeof(usable)); for (int i=0;i<(2<<MAXN);i++) if (Usable(i)) usable[i]=1; } void solve() { memset(mark,0,sizeof(mark)); LL ans=1;//为了防止乘法的时候溢出,可以先用longlong,再转换回int for (int i=1;i<=n;i++) if ((i%2)&&(i%3)) ans=(ans*dp(i))%mod; printf("%d\n",(int)ans); } int main() { scanf("%d",&n); getusable(); solve(); return 0; }
相关文章推荐
- bzoj 2734: [HNOI2012]集合选数 状压DP
- [BZOJ]2734 [HNOI2012] 集合选数 状压DP 思路神题
- 【bzoj2734】【HNOI2012】【集合选数】【状压dp】
- 【bzoj2734】【HNOI2012】【状压DP】集合选数
- (bzoj 2734 [HNOI2012]集合选数)<状压DP>
- BZOJ 2734 HNOI2012 集合选数 状压DP
- bzoj2734[HNOI2012]集合选数 状压DP
- 【BZOJ】【P2734】【HNOI2012】【集合选数】【状压DP】【题解】
- BZOJ 2734 [HNOI2012]集合选数 状压+思路
- bzoj 2734: [HNOI2012]集合选数
- [HNOI2012][BZOJ2734] 集合选数|状态压缩动态规划|思路题
- BZOJ2734 [HNOI2012]集合选数
- BZOJ2734: [HNOI2012]集合选数
- bzoj2734 [HNOI2012]集合选数(状压DP)
- bzoj2734【HNOI2012】集合选数
- [BZOJ2734][HNOI2012]集合选数-状压DP
- bzoj2734: [HNOI2012]集合选数
- BZOJ_2734_[HNOI2012]集合选数_构造+状压DP
- BZOJ2734 HNOI2012集合选数(状压dp)
- bzoj2734: [HNOI2012]集合选数 压状dp