bzoj2734[HNOI2012]集合选数 状压DP
2017-02-21 12:21
239 查看
Description
《集合论与图论》这门课程有一道作业题,要求同学们求出{1, 2, 3, 4, 5}的所有满足以 下条件的子集:若 x 在该子集中,则 2x 和 3x 不能在该子集中。同学们不喜欢这种具有枚举性 质的题目,于是把它变成了以下问题:对于任意一个正整数 n≤100000,如何求出{1, 2,…, n} 的满足上述约束条件的子集的个数(只需输出对 1,000,000,001 取模的结果),现在这个问题就 交给你了。
Input
只有一行,其中有一个正整数 n,30%的数据满足 n≤20。
Output
仅包含一个正整数,表示{1, 2,…, n}有多少个满足上述约束条件 的子集。
Sample Input
4
Sample Output
8
【样例解释】
有8 个集合满足要求,分别是空集,{1},{1,4},{2},{2,3},{3},{3,4},{4}。
HINT
Source
day2
表示一脸不可做..连图的话复杂度爆炸,只能膜一发题解.
真的强..
因为选了一个数x,不能选2x,3x.那么我们可以建一个矩阵.
x 2x 4x ….
3x 6x 12x
9x 18x 36x
向下乘3,向左乘2.
那么我们只要状压dp一下,相邻不能选的方案数,就可以了,矩阵最多18列11行,不会超.
但是一个不能包括所有,所以要有多个矩阵,不同矩阵之间的数可以同时出现,所以我们可以用乘法原理直接乘就可以了.
dp的时候判断左右相邻不同用(y&y>>1==0),上下相邻用(x&y==0),x是上一行的状态。
具体细节看代码巴。
《集合论与图论》这门课程有一道作业题,要求同学们求出{1, 2, 3, 4, 5}的所有满足以 下条件的子集:若 x 在该子集中,则 2x 和 3x 不能在该子集中。同学们不喜欢这种具有枚举性 质的题目,于是把它变成了以下问题:对于任意一个正整数 n≤100000,如何求出{1, 2,…, n} 的满足上述约束条件的子集的个数(只需输出对 1,000,000,001 取模的结果),现在这个问题就 交给你了。
Input
只有一行,其中有一个正整数 n,30%的数据满足 n≤20。
Output
仅包含一个正整数,表示{1, 2,…, n}有多少个满足上述约束条件 的子集。
Sample Input
4
Sample Output
8
【样例解释】
有8 个集合满足要求,分别是空集,{1},{1,4},{2},{2,3},{3},{3,4},{4}。
HINT
Source
day2
表示一脸不可做..连图的话复杂度爆炸,只能膜一发题解.
真的强..
因为选了一个数x,不能选2x,3x.那么我们可以建一个矩阵.
x 2x 4x ….
3x 6x 12x
9x 18x 36x
向下乘3,向左乘2.
那么我们只要状压dp一下,相邻不能选的方案数,就可以了,矩阵最多18列11行,不会超.
但是一个不能包括所有,所以要有多个矩阵,不同矩阵之间的数可以同时出现,所以我们可以用乘法原理直接乘就可以了.
dp的时候判断左右相邻不同用(y&y>>1==0),上下相邻用(x&y==0),x是上一行的状态。
具体细节看代码巴。
#include<iostream> #include<cstring> #include<cstdio> #include<cstdlib> #include<algorithm> #include<queue> #include<cmath> #include<map> #include<queue> #define fo(i,a,b) for(int i=a;i<=b;i++) using namespace std; const int mo=1e9+1; typedef long long ll; ll tot=1; int bin[20],n,a[20][20],b[20],f[20][2048]; bool bz[100005]; inline int cal(int x) { memset(b,0,sizeof(b)); a[1][1]=x; fo(i,2,18) if (a[i-1][1]*2<=n) a[i][1]=a[i-1][1]*2; else a[i][1]=n+1; fo(i,1,18) fo(j,2,11) if (a[i][j-1]*3<=n) a[i][j]=a[i][j-1]*3; else a[i][j]=n+1; fo(i,1,18) fo(j,1,11) if (a[i][j]<=n) { bz[a[i][j]]=1; b[i]+=bin[j-1]; } fo(i,0,18) fo(j,0,b[i]) f[i][j]=0; f[0][0]=1; fo(i,0,17) fo(x,0,b[i]) { if (f[i][x]) fo(y,0,b[i+1]) if (((x&y)==0)&&((y&(y>>1))==0)) f[i+1][y]=(f[i][x]+f[i+1][y])%mo; } return f[18][0]; } int main() { scanf("%d",&n); bin[0]=1; fo(i,1,19)bin[i]=bin[i-1]<<1; fo(i,1,n) if (!bz[i])tot=(tot*cal(i))%mo; printf("%lld\n",tot); return 0; }
相关文章推荐
- 【bzoj2734】【HNOI2012】【集合选数】【状压dp】
- [BZOJ]2734 [HNOI2012] 集合选数 状压DP 思路神题
- (bzoj 2734 [HNOI2012]集合选数)<状压DP>
- 【bzoj2734】【HNOI2012】【状压DP】集合选数
- 【状压DP】BZOJ2734-[HNOI2012]集合选数
- BZOJ 2734 HNOI2012 集合选数 状压DP
- bzoj 2734: [HNOI2012]集合选数 状压DP
- bzoj2734: [HNOI2012]集合选数 压状dp
- bzoj 2734: 2734: [HNOI2012]集合选数 (状压DP)
- bzoj 2734: [HNOI2012]集合选数
- [BZOJ2734][HNOI2012]集合选数(状压DP)
- 【bzoj2734】[HNOI2012]集合选数
- BZOJ 2734: [HNOI2012]集合选数 [DP 状压 转化]
- BZOJ 2734: [HNOI2012]集合选数 乱搞DP
- bzoj 2734 [HNOI2012]集合选数 dp
- BZOJ2734: [HNOI2012]集合选数
- 【BZOJ】2734: [HNOI2012]集合选数
- BZOJ 2734: [HNOI2012]集合选数( 状压dp )
- 【BZOJ 2734】[HNOI2012]集合选数 状压dp
- bzoj2734:[HNOI2012]集合选数(状压DP)