【bzoj2734】【HNOI2012】【集合选数】【状压dp】
2016-03-31 18:39
302 查看
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}。
题解:我们把x之间的关系写成一些矩阵。
x 3x 9x ...
2x 6x 18x ...
4x 12x 24x ...
...
现在问题变成了给你一些矩阵,要求不能选相邻的数,求方案数。
显然这个矩阵的长宽是log级的。
所以对于每个矩阵直接状压dp
最后把所有矩阵的答案乘起来即可。
代码:
#include<iostream> #include<cstdio> #include<cstring> #define P 1000000001 using namespace std; int f[2][1<<12],n,vis[1<<12]; long long ans(1); int cal(int x){ int i,j,t,a,b,pre(0),ans(0); memset(f,0,sizeof(f)); f[1][0]=1; for (i=0;x*(1<<i)<=n;i++){ memset(f+(i&1),0,sizeof(f)>>1); for (j=0,t=1;x*t*(1<<i)<=n;j++,t*=3); for (a=0;a<(1<<pre);a++) if (vis[a]) for (b=0;b<(1<<j);b++) if (vis[b]&&((a&b)==0)) f[i&1][b]+=f[~i&1][a],f[i&1][b]%=P; pre=j; } //cout<<f[0][0]<<' '<<f[0][1]<<endl; for (j=0;j<(1<<pre);j++) ans+=f[~i&1][j],ans%=P; return ans; } int main(){ scanf("%d",&n); for (int i=0;i<(1<<12);i++) if (!(i<<1&i)&&!(i>>1&i)) vis[i]=1; for (int i=1;i<=n;i++) if (i%2&&i%3) ans*=cal(i),ans%=P; cout<<ans<<endl; }
相关文章推荐
- XAPIAN简介(一)
- linux中vi的使用
- 大数据作协框架Oozie
- html5开发之viewport使用
- Bzoj2631:tree(伍一鸣):LCT
- Java的数组
- 分享一个好的钢琴论坛,可以查钢琴价格哦
- easyui tree 增加参数
- 在Eclipse中进行HotSpot的源码调试--转
- 代码重构(六):代码重构完整案例
- Git分布式版本控制学习
- JQuery选择器收藏
- HDU 1157 Who's in the Middle
- kafka原理
- 移动端头部文件详解(二)
- Linux查看物理CPU个数、核数、逻辑CPU个数
- 锁表
- #调整随机森林的参数(调整n_estimators随机森林中树的数量默认10个树,精度递增显著,但并不是越多越好),加上verbose=True,显示进程使用信息
- CentOS7.2详细安装步骤(二)
- 将Hdfs数据往Hbase表中导入