Numbers within a range that can be expressed as power of two numbers - GeeksforGeeks

24 Apr, 2018
Given two integers L and R. Find the number of perfect powers in the given range [L, R]. A number x is said to be perfect power if there exists some integers a > 0, p > 1 such that x = ap.
Examples :
Input : 1 4
Output : 2
Explanation : 
Suitable numbers are 1 and 4 where 1
can be expressed as 1 = 12 
and 4 can be expressed as 4 = 22

Input : 12 29
Output : 3
Explanation : 
Suitable numbers are 16, 25 and 27.

Prerequisites : Check if a number can be expressed as x^y, Binary Search and Perfect power (1, 4, 8, 9, 16, 25, 27, ...)
Approach : Let’s fix some power p. It’s obvious that there are no more than 1018/p numbers x such that xp doesn’t exceed 1018 for a particular p. At the same time, only for p = 2 this amount is relatively huge, for all other p ≥ 3 the total amount of such numbers will be of the order of 106. There are 109 squares in the range [1, 1018], so can’t store them to answer our query.
Either, generate all of powers for p ≥ 2 and dispose of all perfect squares among them or generate only odd powers of numbers like 3, 5, 7, etc. Then answer to query (L, R) is equal to the amount of generated numbers between L and R plus some perfect squares in range.
The number of perfect squares in the range is the difference of floor value of square root of R and floor value of square root of (L – 1), i.e. (floor(sqrt(R)) – floor(sqrt(L – 1)). Note that due to precision issues the standard sqrt might produce incorrect values, so either use binary search or sqrtl inbuilt function defined in cmath (Check here for more description of sqrtl).To generate those odd powers of numbers. First of all, do precomputation of finding such numbers that can be expressed as power of some number upto 1018 so that we can answer many queries and no need to process them again and again for each query. Start by iterating a loop from 2 to 106 (since we are calculating for powers p ≥ 3 and 106 is the maximum number whose power raised to 3 cannot exceed 1018), for each value we insert its square into a set and check further if that value is already a perfect square (already present in the set), we do not find any other powers of that number (since any power of a perfect square is also a perfect square). Otherwise, run an inside loop to find odd powers of the number until it exceeds 1018 and insert into another set say ‘s’. By this approach, we haven’t pushed any perfect square in the set ‘s’.
The number of perfect squares in the range is the difference of floor value of square root of R and floor value of square root of (L – 1), i.e. (floor(sqrt(R)) – floor(sqrt(L – 1)). Note that due to precision issues the standard sqrt might produce incorrect values, so either use binary search or sqrtl inbuilt function defined in cmath (Check here for more description of sqrtl).
To generate those odd powers of numbers. First of all, do precomputation of finding such numbers that can be expressed as power of some number upto 1018 so that we can answer many queries and no need to process them again and again for each query. Start by iterating a loop from 2 to 106 (since we are calculating for powers p ≥ 3 and 106 is the maximum number whose power raised to 3 cannot exceed 1018), for each value we insert its square into a set and check further if that value is already a perfect square (already present in the set), we do not find any other powers of that number (since any power of a perfect square is also a perfect square). Otherwise, run an inside loop to find odd powers of the number until it exceeds 1018 and insert into another set say ‘s’. By this approach, we haven’t pushed any perfect square in the set ‘s’.
Hence the final answer would be sum of number of perfect squares in the range and difference of upper value of R and lower value of L (using binary search).Below is the implementation of above approach in C++.
// CPP Program to count the numbers// within a range such that number// can be expressed as power of some// other number#include <bits/stdc++.h>  using namespace std;  #define N 1000005#define MAX 1e18  // Vector to store powers greater than 3vector<long int> powers;  // set to store perfect squaresset<long int> squares;  // set to store powers other// than perfect squaresset<long int> s;  void powersPrecomputation(){    for (long int i = 2; i < N; i++)     {        // pushing squares        squares.insert(i * i);          // if the values is already        // a perfect square means        // present in the set        if (squares.find(i) != squares.end())                continue;          long int temp = i;          // run loop until some        // power of current number        // doesn't exceed MAX        while (i * i <= MAX / temp)         {            temp *= (i * i);              /* pushing only odd powers            as even power of a number            can always be expressed as             a perfect square which is            already present in set squares  */            s.insert(temp);        }    }      // Inserting those sorted     // values of set into a vector    for (auto x : s)        powers.push_back(x);}  long int calculateAnswer(long int L, long int R){    // calculate perfect squares in     // range using sqrtl function    long int perfectSquares = floor(sqrtl(R)) -                             floor(sqrtl(L - 1));      // calculate upper value of R     // in vector using binary search    long int high = (upper_bound(powers.begin(),             powers.end(), R) - powers.begin());      // calculate lower value of L     // in vector using binary search    long int low = (lower_bound(powers.begin(),            powers.end(), L) - powers.begin());      // add into final answer    perfectSquares += (high - low);      return perfectSquares;}  // Driver Codeint main(){    // precompute the powers    powersPrecomputation();      // left value of range    long int L = 12;          // right value of range    long int R = 29;      cout << "Number of powers between " << L             << " and " << R << " = " <<             calculateAnswer(L, R) << endl;      L = 1;    R = 100000000000;      cout << "Number of powers between " << L            << " and " << R << " = " <<             calculateAnswer(L, R) << endl;      return 0;}
Number of powers between 12 and 29 = 3
Number of powers between 1 and 100000000000 = 320990

cpp-set
number-theory
Searching
Technical Scripter
Searching
number-theory
Writing code in comment?
Please use ide.geeksforgeeks.org,
generate link and share the link here.
Comments
Old Comments
Best First Search (Informed Search)
3 Different ways to print Fibonacci series in Java
Find whether an array is subset of another array | Added Method 5
Program to remove vowels from a String
Recursive Programs to find Minimum and Maximum elements of array
Find common elements in three sorted arrays
Find closest number in array
Binary Search In JavaScript
Find the row with maximum number of 1s
Interpolation search vs Binary search