给定Q个查询,每个查询由两个整数L和R组成,任务是查找L和R之间的总数(包括两个端点),它们的二进制表示形式中最多有三个设置位。
例子:
Input : Q = 2
L = 3, R = 7
L = 10, R = 16
Output : 5
6
For the first query, valid numbers are 3, 4, 5, 6, and 7.
For the second query, valid numbers are 10, 11, 12, 13, 14 and 16.
先决条件:位操作和二进制搜索
方法1(简单) :天真的方法是遍历L和R之间的所有数字,并在每个数字中找到设置的位数。如果一个数字的设置位数不超过3个,则递增计数器变量。返回答案作为计数器。注意:由于数字L和R可能具有较大的值(最多10 18 ),因此此方法效率很低。
方法2(有效) :这里需要的一种有效方法是预计算。由于L和R的值在[0,10 18 ]范围内(包括两端值),因此它们的二进制表示形式最多可以具有60位。现在,由于有效数字是具有最多3个设置位的数字,因此可以通过生成60个位数少于或等于3个设置位的所有位序列来找到它们。这可以通过为(0,60)中的所有i,j,k固定ith , jth和kth位来完成。一旦所有有效数字按排序顺序生成,请应用二进制搜索来查找位于给定范围内的那些数字的计数。
下面是上述方法的实现。
C++
// CPP program to find the numbers
// having atmost 3 set bits within
// a given range
#include
using namespace std;
#define LL long long int
// This function prints the required answer for each query
void answerQueries(LL Q, vector > query)
{
// Set of Numbers having at most 3 set bits
// arranged in non-descending order
set s;
// 0 set bits
s.insert(0);
// Iterate over all possible combinations of
// i, j and k for 60 bits
for (int i = 0; i <= 60; i++) {
for (int j = i; j <= 60; j++) {
for (int k = j; k <= 60; k++) {
// 1 set bit
if (j == i && i == k)
s.insert(1LL << i);
// 2 set bits
else if (j == k && i != j) {
LL x = (1LL << i) + (1LL << j);
s.insert(x);
}
else if (i == j && i != k) {
LL x = (1LL << i) + (1LL << k);
s.insert(x);
}
else if (i == k && i != j) {
LL x = (1LL << k) + (1LL << j);
s.insert(x);
}
// 3 set bits
else {
LL x = (1LL << i) + (1LL << j) + (1LL << k);
s.insert(x);
}
}
}
}
vector validNumbers;
for (auto val : s)
validNumbers.push_back(val);
// Answer Queries by applying binary search
for (int i = 0; i < Q; i++) {
LL L = query[i].first;
LL R = query[i].second;
// Swap both the numbers if L is greater than R
if (R < L)
swap(L, R);
if (L == 0)
cout << (upper_bound(validNumbers.begin(), validNumbers.end(),
R) - validNumbers.begin()) << endl;
else
cout << (upper_bound(validNumbers.begin(), validNumbers.end(),
R) - upper_bound(validNumbers.begin(), validNumbers.end(),
L - 1)) << endl;
}
}
// Driver Code
int main()
{
// Number of Queries
int Q = 2;
vector > query(Q);
query[0].first = 3;
query[0].second = 7;
query[1].first = 10;
query[1].second = 16;
answerQueries(Q, query);
return 0;
}
Java
// Java program to find the numbers
// having atmost 3 set bits within
// a given range
import java.util.*;
import java.io.*;
public class RangeQueries {
//Class to store the L and R range of a query
static class Query {
long L;
long R;
}
//It returns index of first element which is grater than searched value
//If searched element is bigger than any array element function
// returns first index after last element.
public static int upperBound(ArrayList validNumbers,
Long value)
{
int low = 0;
int high = validNumbers.size()-1;
while(low < high){
int mid = (low + high)/2;
if(value >= validNumbers.get(mid)){
low = mid+1;
} else {
high = mid;
}
}
return low;
}
public static void answerQueries(ArrayList queries){
// Set of Numbers having at most 3 set bits
// arranged in non-descending order
Set allNum = new HashSet<>();
//0 Set bits
allNum.add(0L);
//Iterate over all possible combinations of i, j, k for
// 60 bits. And add all the numbers with 0, 1 or 2 set bits into
// the set allNum.
for(int i=0; i<=60; i++){
for(int j=0; j<=60; j++){
for(int k=0; k<=60; k++){
//For one set bit, check if i, j, k are equal
//if yes, then set that bit and add it to the set
if(i==j && j==k){
allNum.add(1L << i);
}
//For two set bits, two of the three variable i,j,k
//will be equal and the third will not be. Set both
//the bits where two variabls are equal and the bit
//which is not equal, and add it to the set
else if(i==j && j != k){
long toAdd = (1L << i) + (1L << k);
allNum.add(toAdd);
}
else if(i==k && k != j){
long toAdd = (1L << i) + (1L << j);
allNum.add(toAdd);
}
else if(j==k && k != i){
long toAdd = (1L << j) + (1L << i);
allNum.add(toAdd);
}
//Setting all the 3 bits
else {
long toAdd = (1L << i) + (1L << j) + (1L << k);
allNum.add(toAdd);
}
}
}
}
//Adding all the numbers to an array list so that it can be sorted
ArrayList validNumbers = new ArrayList<>();
for(Long num: allNum){
validNumbers.add(num);
}
Collections.sort(validNumbers);
//Answer queries by applying binary search
for(int i=0; i queries = new ArrayList<>();
Query q1 = new Query();
q1.L = 3;
q1.R = 7;
Query q2 = new Query();
q2.L = 10;
q2.R = 16;
queries.add(q1);
queries.add(q2);
answerQueries(queries);
}
}
时间复杂度:O((最大位数) 3 + Q * logN),其中Q是查询数,N是包含所有有效数的集合的大小。 l有效数字。