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库
今天适合膜拜大佬,%%%%%%%