Almost prime numbers are positive integers of the form p^k, where is a prime number and k \ge 2. For example, the numbers 4, 8, 16, 32, 9, 81, ... are all almost prime numbers.
Since high < 10^{12}, based on the definition of an almost prime number, the possible values of the prime number must satisfy the inequality p < 10^6.
We'll generate an array of length 10^6, where primes[i] = 1 if is a prime number, and primes[i] = 0 otherwise.
Next, we construct an array containing all almost prime numbers not exceeding 10^{12}. The number of such values is , and we sort them in ascending order.
Let f(a, b) represent the number of almost prime numbers in the range . Then:
The number of almost prime numbers in the range is equal to the index at which number can be inserted into array to maintain its sorted order.
This index can be found using binary search — via the upper_bound function.
Example
Let's generate all almost prime numbers in the range from to .
First, write down the powers of the prime number that do not exceed :
Then, write down the powers of :
Then, the powers of :
And finally, the powers of :
The square of is , which is greater than , so the powers of and higher primes do not fall within the given range.
After sorting, we get the array:
Let's now consider the second test case: . In this range, the following almost prime numbers are found: 4, 8, 9, 16. Their total count is .
Algorithm implementation
Let's declare global arrays. Almost prime numbers that do not exceed 10^{12} are powers of prime numbers that do not exceed MAX = 10^6.
All the found almost prime numbers will be stored in the array .
#define MAX 1000010
char primes[MAX];
long long m[MAX];To check whether numbers are prime, we’ll generate the array .
void gen_primes(void)
{
for (int i = 0; i < MAX; i++) primes[i] = 1;
for (int i = 2; i < sqrt(MAX); i++)
if (primes[i])
for (int j = i * i; j < MAX; j += i) primes[j] = 0;
}The main part of the program.
gen_primes();For each prime number , add its powers i^2, i^3, i^4, ... to the array , until the current power exceeds 10^{12}. The variable holds the number of almost prime numbers added to the array . Since the values of almost prime numbers do not exceed 10^{12}, we need to use -bit integers (type long long) for storage and calculations.
for(i = 2; i < MAX; i++)
if (primes[i])
{
long long temp = 1LL*i*i;
while(temp < 1LL*MAX*MAX)
{
m[ptr++] = temp;
temp *= i;
}
}Sort the array using the STL standard library.
sort(m,m+ptr);Read the number of input test cases , and for each interval , compute and print the value
Each such query is processed in O(log_2~ptr) time using binary search.
scanf("%d", &tests);
while(tests--)
{
scanf("%lld %lld", &l, &h);
printf("%d\n", upper_bound(m,m+ptr,h) - upper_bound(m,m+ptr,l-1));
}Java implementation
import java.util.*;
public class Main
{
public static ArrayList<Long> primes = new ArrayList<Long>();
public static void GenPrimes()
{
final int MAX_SIZE = 1000001;
BitSet bits = new BitSet(MAX_SIZE);
bits.set(2, MAX_SIZE, true);
for (int i = 2; i < Math.sqrt(MAX_SIZE); i++)
{
if (bits.get(i))
for (int j = i * i; j < MAX_SIZE; j += i)
bits.set(j, false);
}
for (int i = 2; i < MAX_SIZE; i++)
if (bits.get(i))
{
long temp = i;
while ((temp *= i) < 1000000000000L)
primes.add(temp);
}
primes.add(1000000000001L);
Collections.sort(primes);
}
public static void main(String[] args)
{
Scanner con = new Scanner(System.in);
int tests = con.nextInt();
GenPrimes();
for(int i = 0; i < tests; i++)
{
Long low = con.nextLong();
Long high = con.nextLong();
int lIndex = Collections.binarySearch(primes, low);
if (lIndex < 0) lIndex = -(lIndex + 1);
int hIndex = Collections.binarySearch(primes, high);
if (hIndex < 0) hIndex = -(hIndex + 1); else hIndex++;
System.out.println(hIndex - lIndex);
}
}
}