📜  须藤安置|范围查询

📅  最后修改于: 2021-09-16 10:56:50             🧑  作者: Mango

给定 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 现场工作专业课程学生竞争性编程现场课程