J集合选数
题意:求出{1, 2, 3, 4, 5}的所有满足以 下条件的子集:若 x 在该子集中,则 2x 和 3x 不能在该子集中。(结果对1e9+1取模)
分析:
首先,什么样的数才会产生排斥呢?(选了这个不能选那个) 显然是之比是2或3的啦
其次,很容易想明白的一点就是每个形如1,2,4,8,3,6,9.....这种以一个小的数通过*2*3往外延伸的数列,他们两两之间是互不干扰的
比如,对于从1往外扩展的数列来说可以是1,2,4,8,3,9,27,6,12,24......
他与从5往外扩展的一定是没有交集的,5,10,20,15,30,60……
那么这里自然就很容易想到乘法原理,
也就是说我们解决了每一个这种数列的结果只后只需要乘起来就是最终结果
那么对于每个来说如何解决呢?
首先如果只有之比是2的不能出现在子集中,
第一感觉肯定是“这选相邻的不就完了”
当然,下一秒就会回过神来,显然并不是一眼就能秒出来的(gjk等dalao除外)


这两个题大部分人都过…… 现在大家应该都会迫不及待的打断我“这玩意不就是B题互不侵犯的弱化版吗(甚至弱化到线性)”“这玩意我闭着眼都会打”,
嗯,其实就是用二进制枚举一下这n个2^i里每个位置是否放数,显然如果k&(k>>1)!=0或者k&(k<<1)!=0的话就是不合法的,反之就是合法的
那么现在加一个之比为3的限制又该怎么做呢?
考虑,在没加这个限制之前每个以a为首项的公比为2的数列是互不影响的
而加了这个限制以后这个等比数列里的每一项又与他*3,他*9……扯上了联系
原来是一个一个数(点),加了第一个限制之后变成了一个数列(线)
现在是一个数列(线),再加一个限制,那么变成?
对,变成一个矩阵(面)
所以这也填了开始的坑,为什么要将一个较小数,他*2*3放在一起考虑
而且现在我们知道了,其实开始讲的数列他不是数列而是矩阵,大概长这样
1 2 4 8 16
3 6 12 24 48
9 18 36 72 144
……
而这个又该怎么才能排除掉不合法的呢?
“这不还是B题的弱化版吗”“行了,我会了,再见了您嘞”
没错,这里只需要用状压dp随便搞搞就行,具体的判断条件我相信大家用脚都能打出来,没错就是j&k!=0就不合法,反之合法
最后再梳理一下
首先我们要枚举“最小的数”,这里我用的是判断这个数是否不被2或3整除,
这里类似线性筛,显然如果这个数能被2或3整除,他一定会有一个叫x/2或x/3的来充当“最小的数”
枚举出来最小的数之后,第一列就是x,x*3,x*9,……
然后就是算他每行的列数(x*(3^i)*(2^j)<=n)
最后状压dp随便搞搞就行了
其实这题到这已经基本结束了,但是不知道是不是我菜的原因,又双叒叕t了半天
这边简单介绍几个优化(代码细节)
1.把你单行的判断用一个数组存下状态
比如原来要写for (0 -> 1<<k ) if(k&……)dp[k]……
而现在我们只需要预处理之后 for(0->q.size()) dp[k]……
2.取模->减法


显然减法比取模快不少
3.先用变量代替数组,最后赋值


显然又快不少
4.边干活边赋初值(不用memset,而是在用之前赋初值)




这差的不是一点半点,千万不要一时偷懒调一晚!
最后的最后,再把我关于处理某些细节的代码说一下
1.选出“最小的数”

这里之前说过了
2.计算该行有多少列

这里j是“最小的数”,这里其实应该是以2为底n/j的对数,
我用了个换底公式,好像库里是没有以2为底的函数,只有自然对数和常用对数
具体是为什么这么列式,我觉得真的没啥好说的。。。
3.在何时终止当前行枚举的那层循环

注意,这里的last我有用的,所以最好不要写在循环的第二个分号里(当然这么写再稍微判断一下也是可以的)
4.如何枚举上一层状态,到哪结束
这就是last的意义——记录上一层到q的第多少个,也就是有多少种状态

当然这里的last你看我整个循环,其实他是有可能从上面for的第二个分号出去的,所以开始last要赋成q_cnt而不是0,-1之类无意义的值,防止last还没被赋值就跳出来
这次真没了
代码:
#include<cstdio>
#include<cmath>
using namespace std; #define ll long long const int maxk=2e1+;
const int mod=1e9+;
const int maxn=1e5+; int dp[maxn][maxk];
int q[maxn]; int pd(int x)
{
if(x&(x<<)||x&(x>>)) return ;
return ;
} int pdd(int x,int y)
{
if(x&y) return ;
return ;
} int main()
{
int n;
scanf("%d",&n);
ll ji=;
int hh=(int)(log(n)/log())+;
int q_cnt=;
for(int i=;i<<<hh;++i) if(pd(i)) q[q_cnt++]=i;
for(int i=;i<=n;++i) if(i%&&i%)
{
int last=q_cnt,p=;
for(int j=i;j<=n;j*=,++p)
{
int now=(int)(log(n/j)/log())+1;
for(int k=;k<q_cnt;++k)
{
if(q[k]>=<<now)
{
last=k;
break;
}
if(!p) dp[k][p]=;
else
{
int nowans=;
for(int t=;t<last;++t) if(pdd(q[k],q[t]))
{
nowans+=dp[t][p-];
if(nowans>=mod) nowans-=mod;
}
dp[k][p]=nowans;
}
}
}
int ans=;
for(int j=;j<last;++j)
{
ans+=dp[j][p-];
if(ans>=mod) ans-=mod;
}
ji*=(ll)ans,ji%=(ll)mod;
}
printf("%lld",ji);
return ;
}
J集合选数的更多相关文章
- 【BZOJ-2732】集合选数 状压DP (思路题)
2734: [HNOI2012]集合选数 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 1070 Solved: 623[Submit][Statu ...
- bzoj 2734: [HNOI2012]集合选数 状压DP
2734: [HNOI2012]集合选数 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 560 Solved: 321[Submit][Status ...
- 【BZOJ2734】【HNOI2012】集合选数(状态压缩,动态规划)
[BZOJ2734][HNOI2012]集合选数(状态压缩,动态规划) 题面 Description <集合论与图论>这门课程有一道作业题,要求同学们求出{1, 2, 3, 4, 5}的所 ...
- BZOJ_2734_[HNOI2012]集合选数_构造+状压DP
BZOJ_2734_[HNOI2012]集合选数_构造+状压DP 题意:<集合论与图论>这门课程有一道作业题,要求同学们求出{1, 2, 3, 4, 5}的所有满足以 下条件的子集:若 x ...
- 2734: [HNOI2012]集合选数
2734: [HNOI2012]集合选数 链接 分析: 转化一下题意. 1 3 9 27... 2 6 18 54... 4 12 36 108... 8 24 72 216... ... 写成这样的 ...
- [HNOI2012]集合选数 --- 状压DP
[HNOI2012]集合选数 题目描述 <集合论与图论>这门课程有一道作业题,要求同学们求出\({1,2,3,4,5}\)的所有满足以 下条件的子集:若 x 在该子集中,则 2x 和 3x ...
- 【BZOJ-2734】集合选数 状压DP (思路题)
2734: [HNOI2012]集合选数 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 1070 Solved: 623[Submit][Statu ...
- bzoj2734【HNOI2012】集合选数
2734: [HNOI2012]集合选数 Time Limit: 10 Sec Memory Limit: 128 MB Submit: 831 Solved: 487 [Submit][Stat ...
- 状压DP之集合选数
题目 [HNOI2012]集合选数 <集合论与图论>这门课程有一道作业题,要求同学们求出{1, 2, 3, 4, 5}的所有满足以 下条件的子集:若 x 在该子集中,则 2x 和 3x 不 ...
随机推荐
- Array(数组)对象-->数组长度的获取以及增减
1.数组长度的获取: 属性:length 用法:数组名.length 举例:求一个数组的长度 var arr = [1,2,3,4,5] var arr_length = arr.length con ...
- IntelliJ IDEA 在方法大括号中{}点击回车多出一个},如何取消
在 File - settings - Editor - General- Smart Keys - Enter 去掉 Insert pair '}' 的对勾就可以了
- 数据结构和算法(Golang实现)(21)排序算法-插入排序
插入排序 插入排序,一般我们指的是简单插入排序,也可以叫直接插入排序.就是说,每次把一个数插到已经排好序的数列里面形成新的排好序的数列,以此反复. 插入排序属于插入类排序算法. 除了我以外,有些人打扑 ...
- 【python实现卷积神经网络】池化层实现
代码来源:https://github.com/eriklindernoren/ML-From-Scratch 卷积神经网络中卷积层Conv2D(带stride.padding)的具体实现:https ...
- python2.7安装pip
- 如何教零基础的人认识Python
前言 文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理. 作者: 编程派 PS:如有需要Python学习资料的小伙伴可以加点击下方链接 ...
- stand up meeting 1-6
今日更新: 1.修复初始最佳战绩显示bug: 初始为击败全国0% 用户 2.挑战结果界面显示“哎,今天的饭又白吃了,回去多吃两碗###”, 去除API返回string中的“###”. 3.分享模块初 ...
- NK16
C 小石的海岛之旅 链接:https://ac.nowcoder.com/acm/contest/949/C来源:牛客网 暑假到了,小石和小雨到海岛上玩. 从水平方向看海岛可以看成 nnn个小块,每一 ...
- selenium 窗口的切换
窗口切换需要用到一个关键词:句柄,每个窗口唯一的标识 获取句柄的方法:driver.getWindowHandle(); 下面的例子是点击京东页面,跳转到京东手机页面,然后关闭京东页面 driver. ...
- shiro:集成Springboot(六)
1:导入相关依赖 <!--thymeleaf 模板引擎依赖包--> <dependency> <groupId>org.springframework.boot&l ...