UPC-喜爱(二进制位运算)

山再高,往上爬,总能登顶;
路再长,走下去,定能到达。

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-轮月

发布了32 篇原创文章 · 获赞 5 · 访问量 1161

猜你喜欢

转载自blog.csdn.net/qq_35339563/article/details/105065485
今日推荐