题意:已知D(0<=D<2^31)、s1、s2,其中L为D转化为二进制数时1的个数,题目保证s1<=L<=s2,求一个数,满足以下条件:

1、比D大

2、转化为二进制时1的个数在[s1, s2]内

3、找出满足1、2条件的最小数字

分析:

1、首先将D加1,假设该数为x,求出x转化为二进制时1的个数cnt。

2、若s1<=cnt<=s2,则输出x

3、若cnt<s1,则应当增加1的数目,因为要保证找到的数字最小,所以要从二进制数的最右边开始改变。

方法:从右向左,将找到第一个0变为1,假设找到的这个0的位数为i(从右往左数第一个数字位数为0,以此类推),那将该数字变为1时,D会增加2^i。(eg:5的二进制数位101,将第1位的0变为1,则是111,转化为十进制是7,,5变成7增加了2^1)

4、若cnt>s1,则应当减少1的数目,因为要保证找到的数字最小,所以要从二进制数的最右边开始改变。

方法:从右向左,将找到第一个1变为0,假设找到的这个1的位数为i(从右往左数第一个数字位数为0,以此类推),那将该数字变为0时,D会增加2^i。(eg:6的二进制数位110,将第1位的1变为0,则是1000,转化为十进制是8,,6变成8增加了2^1)

5、循环上述操作直到满足条件。

6、如上解法的原因有二:

(1)因为是在二进制上操作,所以当cnt<s1加1时,就不必要调用get函数求二进制中1的个数(如果这道题想暴力水过的话,就容易明白这句话)

(2)最最主要的原因是,它跳过了许多不满足的中间数字。

  如以下例子:D = 4, s1 = 1, s2 = 1,为了方便理解可以看下表。

按照该题的解题思路,D+1为5,那么因为其二进制数中1的个数是2,cnt>s2,因此按代码操作后D为6,仍cnt>s2,继续按代码操作,可得D为8,跳过了D为7的情况,这种跳过的现象数越大越明显,此处不再举例。

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cctype>
#include<cmath>
#include<iostream>
#include<sstream>
#include<iterator>
#include<algorithm>
#include<string>
#include<vector>
#include<set>
#include<map>
#include<stack>
#include<deque>
#include<queue>
#include<list>
#define Min(a, b) a < b ? a : b
#define Max(a, b) a < b ? b : a
typedef long long ll;
typedef unsigned long long llu;
const int INT_INF = 0x3f3f3f3f;
const int INT_M_INF = 0x7f7f7f7f;
const ll LL_INF = 0x3f3f3f3f3f3f3f3f;
const ll LL_M_INF = 0x7f7f7f7f7f7f7f7f;
const int dr[] = {, , -, };
const int dc[] = {-, , , };
const double pi = acos(-1.0);
const double eps = 1e-;
const int MAXN = + ;
const int MAXT = + ;
using namespace std;
int a[MAXN];
int get(ll n){//求二进制数中1的个数,边求边将D+1的二进制数依次存入数组a,便于之后从右向左找第一个1或第一个0
int k = ;
int cnt = ;
while(n){
a[k++] = n % ;
if(n & ) ++cnt;
n >>= ;
}
return cnt;
}
ll POW(int k){//快速幂,因为该题只需求2的k次幂,所以只传了k
ll ans = ll();
ll x = ll();
while(k){
if(k & ) ans *= x;
x *= x;
k >>= ;
}
return ans;
}
int main(){
int T;
scanf("%d", &T);
for(int i = ; i <= T; ++i){
memset(a, , sizeof a);
ll D;
int s1, s2;
scanf("%lld%d%d", &D, &s1, &s2);
printf("Case #%d: ", i);
int cnt = get(++D);
while(){
if(cnt >= s1 && cnt <= s2){
printf("%lld\n", D);
break;
}
else if(cnt < s1){
int k = ;
while(a[k]) ++k;
a[k] = ;//将0变成1,a数组中存的是D的二进制数
D += POW(k);
++cnt;//注意1的个数要增加
}
else if(cnt > s2){
int k = ;
while(!a[k]) ++k;
D += POW(k);//此处可以改为lowbit(D),所需函数如下
cnt = get(D);//1的个数可能不变,可能减少,此处不仅重新计算了D的二进制中1的个数,而且更新了a数组,存进了新的D的二进制数,便于之后从右向左找第一个1或第一个0
}
}
}
return ;
}

PS:lowbit的功能是求2^p,p为x的二进制数中,从右向左数第一个1的位置(从右往左数第一个数字位数为0,以此类推)

int Lowbit(int x){

return x&(-x);

}

eg:若x=9,则9&-9为0000 1001 & 1111 0111,结果为1.(注意该二进制是补码表示,最左边的位为符号位,正数为0 ,负数为1,原码变为补码是按位取反再加1)

而9的二进制数时1001,从右向左数第一个1的位置,其位数为0,所以Lowbit(9) = 2^0 = 1.

HDU 5491 The Next(位运算)的更多相关文章

  1. hdu 1882 Strange Billboard(位运算+枚举)

    http://acm.hdu.edu.cn/showproblem.php?pid=1882 感觉非常不错的一道题. 给一个n*m(1<=n,m<=16)的矩阵,每一个格子都有黑白两面,当 ...

  2. hdu 5023 线段树+位运算

    主要考线段树的区间修改和区间查询,这里有一个问题就是这么把一个区间的多种颜色上传给父亲甚至祖先节点,在这里题目告诉我们最多30颜色,那么我们可以把这30中颜色用二进制储存和传给祖先节点,二进制的每一位 ...

  3. HDU 1882 Strange Billboard(位运算)

    题目链接 题意 : 给你一个矩阵,有黑有白,翻转一个块可以让上下左右都翻转过来,问最少翻转多少次能让矩阵变为全白. 思路 : 我们从第一行开始枚举要翻转的状态,最多可以枚举到2的16次方,因为你只要第 ...

  4. [HDU] 3711 Binary Number [位运算]

    Binary Number Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Tot ...

  5. HDU - 6186 前缀和位运算

    异或操作蒙蔽了我的双眼 以至于没有第一时间想到前缀和与后缀和 水题做的不够多 #include<bits/stdc++.h> #define rep(i,j,k) for(register ...

  6. HDU 3006 The Number of set(位运算 状态压缩)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3006 题目大意:给定n个集合,每个集合都是由大于等于1小于等于m的数字组成,m最大为14.由给出的集合 ...

  7. hdu 4739【位运算】.cpp

    题意: 给出n个地雷所在位置,正好能够组成正方形的地雷就可以拿走..为了简化题目,只考虑平行于横轴的正方形.. 问最多可以拿走多少个正方形.. 思路: 先找出可以组成正方形的地雷组合cnt个.. 然后 ...

  8. HDU 1074 Doing Homework (动态规划,位运算)

    HDU 1074 Doing Homework (动态规划,位运算) Description Ignatius has just come back school from the 30th ACM/ ...

  9. HDU 3605 Escape (网络流,最大流,位运算压缩)

    HDU 3605 Escape (网络流,最大流,位运算压缩) Description 2012 If this is the end of the world how to do? I do not ...

随机推荐

  1. 图形化OpenGL调试器 BuGLe [转]

    BuGLe 结合图形化的OpenGL调试与选择的过滤器上的OpenGL命令流.调试器可以查看状态.纹理.framebuffers ,着色器,而过滤器允许日志,错误检查,自由相机控制,视频捕捉等. 主页 ...

  2. Android开发 将数据保存到SD卡

    前言: 使用Activity的openFileOutput()方法保存文件,文件是存放在手机空间上,一般手机的存储空间不是很大,存放些小文件还行,如果要存放像视频这样的大文件,是不可行的.对于像视频这 ...

  3. Swift3.0相对于2.3语法的一些变化

    前言 : Swift3.0的Swift的第3个主要版本,目标是安全,快速和有表现力,也是第一个有开源社区参与开发的Swift版本.由于语法和API改动比较多,Xcode 8.0 Beta提供了migr ...

  4. LINUX 文件系统如何存储文件 图解

    http://zhuqiuxu.iteye.com/blog/2116023 http://zhuqiuxu.iteye.com/blog/2116168 理解Inode要从文件说起,文件存储在硬盘上 ...

  5. 《C++ 并发编程》- 第1章 你好,C++的并发世界

    <C++ 并发编程>- 第1章 你好,C++的并发世界 转载自并发编程网 – ifeve.com 本文是<C++ 并发编程>的第一章,感谢人民邮电出版社授权并发编程网发表此文, ...

  6. Android(java)学习笔记207:开源项目使用之gif view

    1. 由于android没有自带的gif动画,我在Android(java)学习笔记198:Android下的帧动画(Drawable Animation) 播客中提到可以使用AnimationVie ...

  7. Android(java)学习笔记198:Android下的逐帧动画(Drawable Animation)

    1.帧动画: 帧动画顾名思义,一帧一帧播放的动画就是帧动画. 帧动画和我们小时候看的动画片的原理是一样的,在相同区域快速切换图片给人们呈现一种视觉的假象感觉像是在播放动画,其实不过是N张图片在一帧一帧 ...

  8. css笔记03:伪类first-child

    1. 匹配第一个 <p> 元素 在下面的例子中,选择器匹配作为任何元素的第一个子元素的 p 元素: <html> <head> <style type=&qu ...

  9. 深入理解计算机系统第二版习题解答CSAPP 2.20

    T2Uw(w)=x, x≥0时 T2Uw(w)=x+2w, x<0时 利用上面的公式,重新计算2.19的问题.

  10. Wince 中的图形编程

    图形编程程序当中,笔者主要要和大家讨论的是画刷的创建和使用以及绘图函数,比如2D图像的绘制等等. *画刷的定义: HBRUSH hBrush; *画刷的类型: 1. 系统内置画刷:GetStockOb ...