Official

D - 250-like Number Editorial by en_translator


First, we will show some important observations.

  • By the uniqueness of prime factorization, this problem can be rephrased from “counting the number of \(k\) satisfying certain conditions” to “counting the number of pairs \((p, q)\) satisfying certain conditions.”
  • Since the constraint of this solution says \(N \le 10^{18}\), it holds that \(q \le 10^6\).
    • This is because, if \(q > 10^6\), then \(pq^3 > 10^{18} \ge N\).
  • Moreover, since \(p<q\), we also have \(p \le 10^6\).

From this observation, we will try finding the answer from the list of primes less than \(10^6\) (which can be obtained by Eratosthenes’ sieve).

Here, the following solution is valid.

  • First, fix a prime \(p\), which is taken from the prime list.
  • Next, find the maximum value \(Q\) of prime \(q\) such that \(pq^3 \le N\).
  • Then, for each prime that is greater than \(p\) and less than or equal to \(Q\), it holds that \(pr^3 \le N\). Add the number of such primes to the number of pairs \((p,q)\) satisfying the condition.
    • For example, when \(N=256\), for \(p=2\) we have \(Q=5\); indeed, both \(2 \times 3^3 \le 256\) and \(2 \times 5^3 \le 256\) hold.
  • Do the steps above for all primes \(p\) less than \(10^6\).

When finding \(Q\), one way is to do binary search for each \(p\); alternatively, we can find it in a sliding-window-like manner, since as \(p\) increases, \(Q\) monotonically decreases (actually, non-increasing).

The time complexity of this algorithm except for finding prime list is \(O(P)\) or \(O(P \log P)\), where \(P\) is the number of primes less than or equal to \(\sqrt[3]{N}\).

You have to be careful in finding \(pq^3\). Depending on implementation, it may be that \(p,q \approx 10^6\), thus \(pq^3 \approx 10^{24}\). In such case, the product won’t fit in a 64-bit integer. It can be handled with a technique of estimating the rough value with floating point type like double firsthand, and then finding the detailed value. For more details, please refer to function f in the Sample Code.

Sample Code (C++):

#include<bits/stdc++.h>

using namespace std;
#define MAXP 1000005

vector<long long> prime_list;
void construct_plist(){
  vector<bool> fl(MAXP,false);
  for(int i=2;i<MAXP;i++){
    if(fl[i]){continue;}
    prime_list.push_back(i);
    for(int j=i;j<MAXP;j+=i){fl[j]=true;}
  }
}

long long f(long long p,long long q){
  double est=1;
  est=(q*q*q);
  est*=p;
  if(est>4e18){return 4e18;}
  return p*q*q*q;
}

int main(){
  construct_plist();
  long long n;
  cin >> n;
  long long res=0;
  int sz=prime_list.size();
  int q=sz-1;
  for(int p=0;p<sz;p++){
    while(p<q && f(prime_list[p],prime_list[q])>n){q--;}
    if(p>=q){break;}
    res+=(q-p);
  }
  cout << res << '\n';
  return 0;
}

posted:
last update: