bzoj2734 [HNOI2012]集合选数
2017-03-06 11:53
344 查看
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
4Sample Output
8【样例解释】
有8 个集合满足要求,分别是空集,{1},{1,4},{2},{2,3},{3},{3,4},{4}。
正解:状压dp。
这道题思路太神了。。如果我在考场上肯定就是O(2^n*n)了。。
我们可以把这些数构造成一个矩阵。
1 3 9 27 ...
2 6 18 54 ...
4 12 36 108 ...
...
然后我们可以发现,我们就是要求一个矩阵中相邻的数不选的方案数,并且我们发现,这个矩阵最多只有17行,11列,于是这题就变成了最裸的状压dp了。
但是我们发现,还有一些数没有在矩阵中出现,那么我们每次找到第一个没有出现的数,把它放到1行1列,重新构造一个矩阵。
因为不同矩阵的元素是互不影响的,那么我们把所有矩阵的方案数相乘就行了。
//It is made by wfj_2048~ #include <algorithm> #include <iostream> #include <complex> #include <cstring> #include <cstdlib> #include <cstdio> #include <vector> #include <cmath> #include <queue> #include <stack> #include <map> #include <set> #define inf (1<<30) #define N (100010) #define il inline #define RG register #define ll long long #define rhl 1000000001 #define File(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout) using namespace std; int f[18][1<<18],g[18][18],bin[20],C[20],vis ,n,r,c,res; ll ans; il int gi(){ RG int x=0,q=1; RG char ch=getchar(); while ((ch<'0' || ch>'9') && ch!='-') ch=getchar(); if (ch=='-') q=-1,ch=getchar(); while (ch>='0' && ch<='9') x=x*10+ch-48,ch=getchar(); return q*x; } il void work(){ n=gi(),ans=1,bin[0]=1; for (RG int i=1;i<=18;++i) bin[i]=bin[i-1]<<1; for (RG int p=1;p<=n;++p){ if (vis[p]) continue; memset(g,0,sizeof(g)); g[1][1]=p,vis[p]=1; for (r=2;g[r-1][1]*2<=n;r++) g[r][1]=g[r-1][1]*2,vis[g[r][1]]=1,C[r]=1; r--; for (c=2;g[1][c-1]*3<=n;c++) g[1][c]=g[1][c-1]*3,vis[g[1][c]]=1; C[1]=--c; for (RG int i=2;i<=r;++i) for (RG int j=2;j<=c && g[i][j-1]*3<=n;++j) g[i][j]=g[i][j-1]*3,vis[g[i][j]]=1,C[i]=j; f[0][0]=1,res=0; for (RG int i=1;i<=r;++i) for (RG int j=0;j<bin[C[i]];++j){ f[i][j]=0; if (j&(j<<1) || j&(j>>1)) continue; for (RG int k=0;k<bin[C[i-1]];++k) if (!(j&k)) (f[i][j]+=f[i-1][k])%=rhl; } for (RG int i=0;i<bin[C[r]];++i) (res+=f[r][i])%=rhl; (ans*=(ll)res)%=rhl; } printf("%lld\n",ans); return; } int main(){ File("set"); work(); return 0; }
相关文章推荐
- bzoj 2734: 2734: [HNOI2012]集合选数 (状压DP)
- BZOJ 2734 [HNOI2012]集合选数 状压+思路
- [BZOJ2734][HNOI2012]集合选数(状压DP)
- 【bzoj2734】[HNOI2012]集合选数
- 【bzoj2734】【HNOI2012】【集合选数】【状压dp】
- 【BZOJ 2734】[HNOI2012]集合选数 状压dp
- bzoj 2734 [HNOI2012]集合选数 dp
- (bzoj 2734 [HNOI2012]集合选数)<状压DP>
- bzoj2734 [HNOI2012]集合选数(状压DP)
- 2734: [HNOI2012]集合选数 - BZOJ
- BZOJ 2734: [HNOI2012]集合选数 [DP 状压 转化]
- [BZOJ2734][HNOI2012]集合选数-状压DP
- BZOJ 2734 HNOI2012 集合选数 状压DP
- 【BZOJ2734】【HNOI2012】集合选数(状态压缩,动态规划)
- bzoj 2734: [HNOI2012]集合选数 状压dp
- 【bzoj2734】【HNOI2012】【状压DP】集合选数
- BZOJ2734 HNOI2012集合选数(状压dp)
- 【状压DP】BZOJ2734-[HNOI2012]集合选数
- [bzoj2734][HNOI2012]集合选数
- [BZOJ]2734 [HNOI2012] 集合选数 状压DP 思路神题