Beautiful Number xtuoj1307(位运算,技巧之美)

Beautiful Number

题目描述

如果一个数的二进制中只有1个0,那么我们称这样的数是“美丽数”,比如510=1012。 现在给你一个区间[a,b](1≤a≤b≤1018),求区间内有多少个“美丽数”。

输入

第一行是一个整数K,表示样例的个数。 每个样例是两个整数a和b。

输出

每行输出一个样例的结果。

样例输入

3
1 2
2 5
1 1000000000000000000

样例输出

1
2
1712

提示

第一个例子中,只有2是美丽数;
第二个例子中,2和5是美丽数;

解析: 

    如果我们非常明白二进制和十进制的转换关系我们可以发现

1:1   3:11  7:111 一个数*2相当于二进制左移一位,加一就保证补的哪一位变成1

如3:11 左移 6:110 补1 7:111 那么我们可以得到递推式 I(n)=I(n-1)*2+1

若让某一位为0,只需要减去2的某一次方 即可

那么我们可以写出每一个数的代码   i - ((ull)1 << j)

在这里我们可以发现,从底层原理思考一下比直接无脑暴力舒服的多

当然,我会贴出手写无序集的代码

#include<iostream>
#include<set>
using namespace std;
typedef unsigned long long ull;
const ull fullans = 1000000000000000000;
set<ull> ansset;//去重,手写个无序集也行
int main() {
	ull i;
	int j, k;
	for (i = 1, k = 0; i <= fullans; i = i * 2 + 1, k++ ) {
		for (j = 0; j < k; j++) {
			ansset.insert(i - ((ull)1 << j));
		}
	}
	ansset.insert(i - ((ull)1 << ( k - 1)));//我算除了答案总是少1,我就猜测可能虽然i大于1e18,但是把第二高位变成0可能就在范围内了,试了试真的对
	int t, ans;
	set<ull>::iterator pointer;//类似于指针的东西
	ull a, b;
	cin >> t;
	while (t--) {
		cin >> a >> b;
		ans = 0;
		for (pointer = ansset.begin(); pointer != ansset.end(); pointer++) {//反正1000多个,一个一个试也行
			if (*pointer >= a && *pointer <= b) ans++;
			if (*pointer > b) break;//有序的集合,查到更大的就终止
		}
		cout << ans << endl;
	}
}

没有学c++没关系,这道题也可以写

int wiomset[10005], arrlen = 0;
void insert(int a) {
	int i;
	for (i = 0; i < arrlen; i++) {
		if (a == wiomset[i]) return ;
	}
	wiomset[arrlen] = a;
	arrlen++;
}
去重,原理很简单,但不如STL库

今天适合膜拜大佬,%%%%%%%

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值