P1049 二进制 (三) 题解

描述

二进制是计算机学科中广泛应用的一种数制, 用0和1两个数码来表示数字, 进位规则为"逢二进一"

将一个十进制数字转换为二进制数字的方法如下:

用2整除十进制整数, 可以得到一个商和余数, 再用2去除商, 又会得到一个商和余数, 如此进行, 直到商为小于1时为止, 然后把先得到的余数作为二进制的低位有效位, 后得到的余数作为二进制的高位有效位, 依次排列起来

以13举例, 十进制13 = 二进制1101

13 ÷ 2 = 6 ...... 1

6 ÷ 2 = 3 ...... 0

3 ÷ 2 = 1 ...... 1

1 ÷ 2 = 0 ...... 1

给你两个正整数L和R, 那么从大于等于L到小于等于R的所有正整数中, 二进制中数码"1"出现的次数最多的是哪个数? 如果有多个整数满足条件, 那么你需要输出其中最小的整数


 格式

输入格式

        输入仅包含2个正整数L和R (1≤L≤R≤10^{15}), 由一个空格隔开, 含义如题面所述

输出格式

        输出一个正整数, 含义如题面所述

 


样例

输入样例

8 14

输出样例

11

 


限制

时间限制: 1000 ms

内存限制: 65536 KB


暴力,找点规律,强制从l——>r 一定会超时

#include<bits/stdc++.h>
using namespace std;
#define ll long long 
int lborder[1000];
int rborder[1000];

void calcl(ll i) {
	ll j = 0;
	while (i) {
		lborder[j] = i % 2;
		i /= 2;
		j++;
	}

}
void calcr(ll i) {
	ll j = 0;
	while (i) {
		rborder[j] = i % 2;
		i /= 2;
		j++;
	}

}



int main() {
	ios::sync_with_stdio(false);

	ll l, r, res = 1;
	int cnt = 0;

	cin >> l >> r;
	while (r > res) {
		res = res * 2 + 1;
		cnt++;  //用cnt来初步判断一个cnt,cnt即目前判断的最多1的可能 
	}			//例如l:8 r:14   14<15 最多3个1 
	calcl(l); calcr(r); //将l,和r转成二进制来进行处理 



	res = 0;


	if (l == 1 && r == 1) {  //将特例直接处理 
		res = 1;
	}
	else {
		for (int i = 0; i < cnt; i++)	//将之前判断的1的数量的值给res,并且最多1的最小值 
			res += pow(2, i);
		while (res < l) {
			res += pow(2, cnt);    //如果不满足左边界,进行右移,从数值影响最小的开移,保持尽量小 
			res -= pow(2, cnt - 1);
			cnt--;
		}
	}

	//下面是结果不是判断的 cnt 个1的求解, 
	int maxlen;           //time limit warning 注意处理,处理不好有超时风险 
	if (l == 1 && r == 1) {
		res = 1;
	}
	else if (res > r) {
		cnt++;
		ll tmp = l;
		res = tmp;
		int p = 0;
		while (tmp < r && p <= cnt) {   //根据之前得到的左边界二进制做判断,一位一位去加 
			if (lborder[p] != 1 && p <= cnt && tmp + pow(2, p) <= r) {
				tmp += pow(2, p);
				res = tmp;
			}
			p++;
		}
	}

	cout << res;
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值