📌  相关文章
📜  使用C++ STL在给定范围内的平方自由半素数

📅  最后修改于: 2021-04-21 21:37:48             🧑  作者: Mango

给定两个整数LR (L <= R)。任务是找到L到R(均包括两端)范围内的所有平方自由半素数。

例子:

先决条件: Eratosthenes筛,上下限

理解 :
半素数是形式的数字p*q其中p和q是质数,不一定是质数。全部半质数n只有四个因素1, p, q, p*q其中p和q是仅有的两个素数因子,并且p*q = n

天真的方法:
预先计算所有素数$\sqrt{R}$ 。找出两个素数pq的所有组合,使得p*q = nLR之间。遍历素数的所有组合将使时间复杂度为O(N $^2$) 。但是,该解决方案不适用于较大的LR值。

时间复杂度: O(N ^ 2)

高效方法:
预先计算所有素数$\sqrt{R}$ 。我们可以将找到两个质数p和q的问题分为一个简单的形式。
作为L $\leq$ p*q 我们可以说\frac{L}{p} $\leq$ q 。类似 p*q $\leq$ R 我们可以说 q $\leq$ $\frac{R}{p}
现在问题被简化为找到q的计数,使得 \frac{L}{p} $\leq$ q $\leq$ $\frac{R}{p} 对于所有p。

在这里,我们可以使用二进制搜索来找到\frac{R}{p}从素数列表中减去它的lower_bound的索引\frac{L}{p}从素数列表中找到范围内所有q的计数\frac{L}{p}\frac{R}{p}对于给定的p 。对所有素数p重复上述步骤,将给出给定范围LR的答案

下面是上述方法的实现:

// CPP program to find square free semiprimes in the range
#include 
using namespace std;
  
#define N 78498
  
void Sieve(int pre[])
{
    // Max size of prime array
    int MX = 1e6;
  
    // Array of prime of size 1000001.
    // will be marked true for prime, false otherwise
    // i     = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, ...]
    // prime = {0, 0, 1, 1, 0, 1, 0, 1, 0, 0, ...}
    bool prime[MX + 1];
  
    // i -> keeps track of index of prime 
    // (current integer)
    // idx -> keeps track of index of pre
    int i = 2;
    int idx = 0;
  
    // Initialize all entries to true
    memset(prime, true, sizeof(prime));
  
    // For all i from 2 to MX iterate
    for (i = 2; i <= MX; i++)
    {
        // If i is prime
        if (prime[i]) 
        {
            // Set idx'th index of pre as i and 
            // increment idx after setting the value
            pre[idx++] = i;
  
            // For all multiple of i from 2*i to MX
            // mark them as false i.e. not prime
            for (int j = (i << 1); j <= MX; j += i)
                prime[j] = false;
        }
    }
}
  
// Function to find square free semi primes in the range
int semiPrimeCount(int L, int R)
{
  
    // Array of prime integer
    // will contain first 78498 primes
    // idx = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, ...]
    // pre = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, ...}
    int pre[N];
  
    // Prepare pre array
    Sieve(pre);
  
    // Result of current query
    int res = 0;
  
    // Offset index from start
    int j = 1;
  
    // For all prime integers p in pre 
    // from 2 to sqrt(R) iterate
    for (auto p : pre) {
        // ub_num     = count of all multiple of p less 
        //             than R => p = R/p
        //
        // ub     = iterator of first element greater 
        //         than ub_num in pre
        //
        int ub_num = R / p;
        auto ub = upper_bound(pre + j, pre + N, ub_num);
  
        // lb_num     = count of all multiple of p 
        //             less than L => p = L/p
        // If L is divisible by p increment p by 
        // 1 => p = p+1 = p+(L%p>0)
        //
        // lb     = iterator of first element greater 
        //         than or equal lb_num in pre
      
        int lb_num = (L / p) + ((L % p) > 0);
        auto lb = lower_bound(pre + j, pre + N, lb_num);
  
        // Add the difference between ub and lb
        res += ub - lb;
  
        // Increment j
        j++;
  
        // If prime p is greater than or equal to sqrt(R)
        if (p * p >= R)
            break;
    }
    return res;
}
  
// Driver code
int main()
{
    int L = 10, R = 20;
      
    // Function call
    cout << semiPrimeCount(L, R);
  
    return 0;
}
输出:
3

时间复杂度: O(N * logN)