【题目链接】

ybt 1223:An Easy Problem
OpenJudge NOI 4.6 1455:An Easy Problem

【题目考点】

1. 数制

2. 枚举

【解题思路】

解法1:枚举

要找比给定数字n大的最小的二进制表示中1的个数相同的数字。
先求出n在二进制表示下1的个数。
而后不断枚举比n大的整数,求出其二进制表示中1的个数。如果1的个数与n在二进制下1的个数相同,那么就是找到了比n大的最小的二进制表示中1的个数相同的数字。

分析算法最大复杂度:n最大是10610^6106,二进制下各位全是1的情况,需要枚举的次数最多。
已知一个x位二进制数11⋯1⏟x\underbrace {11\cdots 1}_xx11⋯1​​,各位都是1,其数值为2x−12^x-12x−1。
令2x−1≤1062^x-1 \le 10^62x−1≤106,有x≤log2(106+1)≈19.9x \le log_2(10^6+1)\approx 19.9x≤log2​(106+1)≈19.9,x最大为19。考虑比11⋯1⏟19\underbrace{11\cdots 1}_{19}1911⋯1​​大的最小的也有19个1的二进制数字,为1011⋯1⏟1810\underbrace{11\cdots 1}_{18}101811⋯1​​,相当于比1011⋯1⏟18−11⋯1⏟19=100⋯0⏟18=218=26214410\underbrace{11\cdots 1}_{18}-\underbrace{11\cdots 1}_{19}=1\underbrace{00\cdots 0}_{18} = 2^{18}=262144101811⋯1​​−1911⋯1​​=11800⋯0​​=218=262144。
即对于每个数字,至多枚举262144次,即可得到解,每次枚举拆分数字要循环10次。
对于每个数字,运算复杂度最大为10610^6106数量级。该算法可以支持在1秒内对10~100个数字求比给定数字大的最小的二进制表示中1的个数相同的数字。题目没说要输入多少数字,默认不说就是小于等于100个。所以该算法是可行的。

解法2:找规律

思考,如果该二进制数末尾几位是0,增加1后,其中1的个数就多了1个。再增加1,1的个数始终是变多的。如果数值增加后改变的位置其原位置上都是0,那么1的数量就不会减少到与原有1的数量相同。

原数字:1000
加1:1001
加1:1010
加1:1011
1的数量始终比1000要多。

只有当增加的数值与原位置上的1加和引发进位,才会使1的数量减少

原数字:1011
加1:1100:减少两位1,增加一个进位的1。总共减少一位1。

观察规律可知,第一次1减少的时机发生在最末尾一段连续的1发生进位的时候。
严格描述为:二进制数字d1d2⋯dx⏟x011⋯1⏟k00⋯0⏟m\underbrace{d_1d_2\cdots d_x}_x0\underbrace{11\cdots 1}_{k}\underbrace{00\cdots 0}_{m}xd1​d2​⋯dx​​​0k11⋯1​​m00⋯0​​(d1∼dxd_1\sim d_xd1​∼dx​为任意数字。其中x,m最小为0,k最小为1)
该数字在增加100⋯0⏟m1\underbrace{00\cdots 0}_{m}1m00⋯0​​后发生进位,成为d1d2⋯dx⏟x100⋯0⏟k+m\underbrace{d_1d_2\cdots d_x}_x1\underbrace{00\cdots 0}_{k+m}xd1​d2​⋯dx​​​1k+m00⋯0​​,这次进位增加了1位1,减少了k位1,所以共减少k-1位1。
为了让1的数量不发生改变,应该在末尾增加k-1位1,使数字变为:d1d2⋯dx⏟x100⋯0⏟m+111⋯1⏟k−1\underbrace{d_1d_2\cdots d_x}_x1\underbrace{00\cdots 0}_{m+1}\underbrace{11\cdots 1}_{k-1}xd1​d2​⋯dx​​​1m+100⋯0​​k−111⋯1​​

具体做法为

  1. 将数字转为二进制形式,存入数组
  2. 从低位向高位遍历,如果发现当前位是1且下一位是0的情况,说明找到了最末尾一段连续的1的最高位,记为b。
  3. b+1位置从0变为1。如果b本身是数字的最高位,将b+1位置设为最高位。
  4. 从b开始向低位遍历,计数得到有k个连续的1,同时将遍历到的位置从1变为0。
  5. 从末尾位开始,连续将k-1位0变为1。
  6. 输出数字。

该算法针对每个数字,只是对数字各位进行几遍遍历。小于等于10610^6106的数字的二进制位为20位左右。因而针对每个数字的运算次数都是101010数量级。复杂度远小于方法1。

【题解代码】

解法1:枚举

#include<bits/stdc++.h>
using namespace std;
int main()
{int n, ans;while(cin >> n && n != 0){int ct_n = 0, ct_a;//ct_n:n中1的个数 ct_a:ans中1的个数 for(int a = n; a > 0; a /= 2)if(a%2 == 1)ct_n++;for(ans = n+1; true; ans++){ct_a = 0;for(int a = ans; a > 0; a /= 2)if(a%2 == 1)ct_a++;if(ct_a == ct_n){cout<< ans << endl;break;}}}return 0;
}

解法2:找规律(复杂度低)

//找最末的连续k个1,变为1加上k个0,末尾再添加k-1个1
#include <bits/stdc++.h>
using namespace std;
int main()
{int n, num[50];while(cin >> n && n != 0){memset(num, 0, sizeof(num));int b, ct = 0, ni = 0, ans = 0;//b:最末连续的1的起始位置for(int a = n; a > 0; a /= 2)num[++ni] = a % 2;for(int i = 1; i <= ni; ++i){if(num[i] == 1 && num[i+1] == 0){b = i;break;}}num[b+1] = 1;if(b+1 > ni)ni = b+1;for(int i = b; num[i] != 0; --i){ct++;num[i] = 0;}for(int i = 1; i <= ct-1; ++i)num[i] = 1;for(int i = ni; i >= 1; --i)ans = ans*2+num[i];cout << ans << endl;}     return 0;
}

信息学奥赛一本通 1223:An Easy Problem | OpenJudge NOI 4.6 1455:An Easy Problem相关推荐

  1. 信息学奥赛一本通 1209:分数求和 | OpenJudge NOI 1.13 12:分数求和

    [题目链接] ybt 1209:分数求和 OpenJudge NOI 1.13 12:分数求和 [题目考点] 1. 求最大公约数 2. 求最小公倍数 [解题思路] 求最大公约数,可以用辗转相除法.具体 ...

  2. 信息学奥赛一本通 1294:Charm Bracelet | OpenJudge NOI 2.6 7113:Charm Bracelet | 洛谷 P2871

    [题目链接] ybt 1294:Charm Bracelet OpenJudge NOI 2.6 7113:Charm Bracelet 洛谷 P2871 [USACO07DEC]Charm Brac ...

  3. 信息学奥赛一本通 1173:阶乘和 | OpenJudge NOI 1.6 15 | 洛谷 P1009 [NOIP1998 普及组] 阶乘之和

    [题目链接] ybt 1173:阶乘和 注:一本通上这题,应该把n≤50n\le50n≤50当做n≤100n\le100n≤100来看 OpenJudge NOI 1.6 15:阶乘和 洛谷 P100 ...

  4. 信息学奥赛一本通 1232:Crossing River | OpenJudge NOI 4.6 702:Crossing River

    [题目链接] ybt 1232:Crossing River OpenJudge NOI 4.6 702:Crossing River 一本通里的翻译不够完整,OpenJudge中的英文原题中有对数据 ...

  5. 信息学奥赛一本通 1194:移动路线 | OpenJudge NOI 2.6 2718:移动路线

    [题目链接] ybt 1194:移动路线 OpenJudge NOI 2.6 2718:移动路线 [题目考点] 1. 坐标型动态规划 [解题思路] 解法1:递推 设状态数组dp,dp[i][j]表示从 ...

  6. 信息学奥赛一本通 1193:吃糖果 | OpenJudge NOI 2.6 1944:吃糖果

    [题目链接] OpenJudge NOI 2.6 1944:吃糖果 注:ybt 1193:吃糖果 页面打不开,可以在OpenJudge做该题. [题目考点] 1. 递推/递归 2. 搜索 [解题思路] ...

  7. 信息学奥赛一本通 1191:流感传染 | OpenJudge NOI 2.3 6262:流感传染

    [题目链接] ybt 1191:流感传染 OpenJudge NOI 2.3 6262:流感传染 [题目考点] 1. 二维数组 2. 队列 [解题思路] 用一个字符型二维数组存储各个房间的情况. 1. ...

  8. 信息学奥赛一本通 1185:单词排序 | OpenJudge NOI 1.10 10:单词排序

    [题目链接] ybt 1185:单词排序 OpenJudge NOI 1.10 10:单词排序 [题目考点] 1. 排序 [君义精讲]排序算法 2. 字符串比较 字符数组比较: char s1[N], ...

  9. 信息学奥赛一本通 1182:合影效果 | OpenJudge NOI 1.10 07:合影效果

    [题目链接] ybt 1182:合影效果 OpenJudge NOI 1.10 07:合影效果 [题目考点] 1. 排序 [君义精讲]排序算法 [解题思路] 解法1:将男生身高和女生身高分别排序 将男 ...

最新文章

  1. 使用Java HttpURLConnection抓取网页内容(一)限制返回的网页大小
  2. Opencv cv2.KalmanFilter 鼠标跟踪
  3. ORACLE安装参数修改
  4. Atom不能补全原生JS的一些DOM函数
  5. python3 exe_Windows10下python3和python2同时安装 python2.exe、python3.exe和pip2、pip3设置
  6. 在 NetBeans IDE 中设计 Swing GUI
  7. SpringBoot_web开发-SpringMVC自动配置原理
  8. 函数使用了堆栈的字节超过_在C语言中如何访问堆栈?
  9. 作为函数的mixin
  10. 小学五年级计算机教学工作总结,小学五年级数学教师工作总结(精选8篇)
  11. ORACLE查询表最近更改数据的方法
  12. [转]iPhone发邮件编程
  13. MINITAB(二)
  14. 延时摄影制作软件——GlueMotion for Mac支持m1
  15. StringTokenizer字符串分解器
  16. 计算机开机密码设置要求,电脑开机密码怎么设置,开机密码设置很简单!
  17. vc++中的import的使用
  18. undi是什么意思_undefined是什么意思?
  19. 360浏览器打不开微信的连接服务器,360浏览器打不开网页怎么办-解决360浏览器打不开网页的方法 - 河东软件园...
  20. 笔记本创建wifi热点

热门文章

  1. ASP.NET MVC中如何在客户端进行必要的判断
  2. hover事件注册实例一枚
  3. C#中如何控制播放音乐的声音大小
  4. jQuery+css3实现新年贺卡
  5. 不结婚不生孩子,离婚率15连涨,中国正在步入“低欲望社会”吗?
  6. linux时间戳_10款优秀的 Linux 网络工具
  7. 都啥年代了,求你别再说Redis是单线程了!
  8. 一文讲透Dubbo负载均衡之最小活跃数算法
  9. C++之父:比特币是用C++开发的,我为此感到遗憾。
  10. 很多未解之谜终于有答案了——2018年JVM生态系统报告出炉