给定 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 个设置位的数字,因此通过生成小于或等于 3 个设置位的所有 60 位位序列来找到它们。这可以通过为 (0, 60) 中的所有 i, j, k 固定 i th , j th和 k th位来完成。一次,所有有效数字都按排序顺序生成,应用二分搜索来查找位于给定范围内的那些数字的计数。
下面是上述方法的实现。
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((Maximum Number of Bits) 3 + Q * logN),其中 Q 是查询的数量,N 是包含所有有效数字的集合的大小。 l 有效数字。
如果您希望与专家一起参加现场课程,请参阅DSA 现场工作专业课程和学生竞争性编程现场课程。