山再高,往上爬,总能登顶;
路再长,走下去,定能到达。
UPC-喜爱
题目描述
小s最近对数字情有独钟。他又发现了一种神奇的数字。对于数x,如果它二进制表示中只有一位是0,则x就会被小s所喜爱。比如5,二进制为101,则它被小s所喜爱。
现在,小s想知道,对于一个区间[L,R],有多少数是他所喜爱的。
输入
输入包含多组数据。
输入第一行T,表示数据组数。
每组数组仅有一行,包含两个正整数[L,R]。
输出
对于每组数据输出一行,表示答案。
Sample Input
2
5 10
2015 2015
Sample Output
2
1
Hint
对于30%的数据:L,R≤106,T≤10
对于60%的数据:L,R≤1010,T≤100
对于100%的数据:L,R≤1018,T≤10000
题目解析
这题思路其实很明确,满足要求的数的个数并不是很多,也就一两千个吧,然后把所有的数枚举出来就行了
具体是哪些数呢?
有
0
10
110
101
1110
1101
1011
11110
11101
11011
10111
111110
111101
.
.
.
如此往下,就能看出来规律了
就用位运算
算出
10000减1就可以得1111了
按照这个思路
就把1<<移动多少位然后减一就可以了
然后根据^符号就可以将某一位给变成0了
for (ll i = 2; i <= 61; i++)
{
ll ans = 1;
ans <<= i;
ans–;
for (ll j = 0; j < i - 1; j++)
{
ll temp = (ll)1 << j;
save[q++] = ans ^ temp;
}
}
可以按照这个思路进行枚举,将所有满足的数都存储起来
然后就二分查询就可以了,但是这里的数不是很大,所以直接暴力寻找就可以了
有Sta 和End这两个数包含且之内的所有数,一查询便知
寻找第一个>=Sta的数寻找第一个>End的数,那么这个数的上一位一定是<=Eed的了。
然后确定坐标之后相减就可以了,如果没有解,那么找出来的值一定是一样的,相差就是0
AC时间到
#include<algorithm>
#include<iostream>
#include<string.h>
#include<utility>
#include<stdio.h>
#include<vector>
#include<string>
#include<math.h>
#include<cmath>
#include<queue>
#include<stack>
#include<deque>
#include<map>
#pragma warning(disable:4244)
#define PI 3.1415926536
#pragma GCC optimize(2)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const ll ll_inf = 9223372036854775807;
const int int_inf = 2147483647;
const short short_inf = 32767;
const char char_inf = 127;
inline ll read() {
ll c = getchar(), Nig = 1, x = 0;
while (!isdigit(c) && c != '-')c = getchar();
if (c == '-')Nig = -1, c = getchar();
while (isdigit(c))x = ((x << 1) + (x << 3)) + (c ^ '0'), c = getchar();
return Nig * x;
}
inline void out(ll a)
{
if (a < 0)putchar('-'), a = -a;
if (a >= 10)out(a / 10);
putchar(a % 10 + '0');
}
ll qpow(ll x, ll n, ll mod) {
ll res = 1;
while (n > 0) {
if (n & 1)res = (res * x) % mod;
x = (x * x) % mod; n >>= 1;
}
return res;
}
#define read read()
ll save[1850];//已测满足的数小于1850个数
int main()
{
ll q = 1;//第一位留给0
for (ll i = 2; i <= 61; i++)//61位即可满足1e18
{
ll ans = 1;
ans <<= i;
ans--;
for (ll j = 0; j < i - 1; j++)
{
ll temp = (ll)1 << j;//最开始默认的数字是int型的要转换成long long类型
save[q++] = ans ^ temp;
}
}
sort(save, save + q);//因为选完是乱序,要排个序
ll n = read;
while (n--)//查询步骤
{
ll Sta = read;
ll End = read;
ll L = 0, R = 0;
for (ll i = 0; i < q; i++)//第一个大于等于Sta的数
if (save[i] >= Sta) {
L = i;
break;
}
for (ll i = 0; i < q; i++)//第一个大于End的数
if (save[i] > End)
{
R = i;
break;
}
cout << R - L << endl;
}
}
By-轮月