F - x = a^b Editorial by en_translator
For \(x=1\), letting \(a=1\) makes \(x=a^b\) for all integers \(b\) not less than \(2\), so \(1\) satisfies the condition in the problem statement.
Since such a special case is awkward to consider, we will count how many integers greater than or equal to \(2\) satisfy the condition.
First, let us consider how an integer can be represented if it is represented as \(a^b\).
For example, consider an integer \(x=64=2^6\).
- \(x\) can be represented as \(a^2\) by letting \(a=2^3\).
- \(x\) can be represented as \(a^3\) by letting \(a=2^2\).
- \(x\) can be represented as \(a^6\) by letting \(a=2^1\).
Consider another integer \(x=2985984 = 2^{12} \times 3^6\).
- \(x\) can be represented as \(a^2\) by letting \(a=(2^6 \times 3^3)\).
- \(x\) can be represented as \(a^3\) by letting \(a=(2^4 \times 3^2)\).
- \(x\) can be represented as \(a^6\) by letting \(a=(2^2 \times 3^1)\).
Generally, let \(x=p^lq^mr^n \dots\) be the prime factorization of an integer \(x\). Then:
- for a common divisor \(k\) of \(l,m,n,\dots\), one can take \(a=p^{(l/k)}q^{(m/k)}r^{(n/k)} \dots\) to represent it as \(a^k\).
Thus, it turns out that the desired representation \(x=a^b\) is possible if and only if \(b\) is a divisor of \(g\) not less than \(2\), where \(g = \gcd(l,m,n,\dots)\).
Next, we count possible integers \(a\) for a fixed \(b\).
Specifically, it is sufficient to find the maximum \(a\) with \(a^b \le N\) for each \(b\).
Since \(2^{60} > 10^{18}\), it is sufficient to consider the range \(2 \le b < 60\) under the constraints of this problem.
We can do binary search over \(a\) for each \(b\).
Note that \(a^b\) may overflow;
to avoid this issue, for example, since \(b\) is small, one can try to find the power of \(b\) by naively multiplying it \(b\) times, while every time \(a\) is multiplied, estimate the result using a double type etc. so that we stop calculating if the estimation is large enough.
Now that we obtained the number of integers represented as \(a^b\) for all \(b=2,3,\dots,59\), let us count their union without duplicates.
We use the inclusion-exclusion principle on divisors (article on Japanese) to find the sum.
For the prime factorization \(x=p^lq^mr^n \dots\) of an integer \(x\), we have already shown that a representation \(x=a^b\) exists if and only if \(b\) is a two-or-greater divisor of \(g=\gcd(l,m,n,\dots)\).
Here, let \(g\) be a prime factorization of \(P^LQ^MR^N \dots \). \(x\) can be counted exactly once in the following way:
- Add the case for \(b=P, Q, R, \dots\) (where \(b\) is a product of one prime factor of \(g\)).
- Subtract the case for \(b=PQ, PR, \dots, QR, \dots\) (where \(b\) is a product of two prime factors of \(g\)).
- Add the case for \(b=PQR, \dots\) (where \(b\) is a product of three prime factors of \(g\)).
- \(\vdots\)
The proof can be done in the same way as that of ordinary inclusion-exclusion principle.
Hence, the number of conforming integers can be counted without duplicates or oversight in the following way.
- If \(b\) has a square factor (if \(b\) has multiple prime factors), ignore it.
- Otherwise, if \(b\) has an odd number of prime factors, add it.
- Otherwise, if \(b\) has an even number of prime factors, subtract it.
By implementing them, the problem can be solved in a total of about \(O(\log^3 N)\) time.
Sample code (C++):
#include<bits/stdc++.h>
using namespace std;
vector<long long> pfact(long long x){
vector<long long> res;
for(long long i=2;i*i<=x;i++){
while(x%i==0){
res.push_back(i);
x/=i;
}
}
if(x>1){res.push_back(x);}
return res;
}
long long safe_pow(long long a,long long b){
long long res=1;
for(long long i=0;i<b;i++){
double dres=res;
dres*=a;
if(dres>2e18){return 2e18;}
res*=a;
}
return res;
}
int main(){
long long n;
cin >> n;
long long res=0;
for(long long b=2;b<60;b++){
long long l=2,r=2e9;
while(l<=r){
long long t=(l+r)/2;
if(safe_pow(t,b)>n){r=t-1;}
else{l=t+1;}
}
// a = [2,r] satisfy a^b <= n
vector<long long> pf=pfact(b);
bool same=false;
for(long long i=1;i<pf.size();i++){
if(pf[i-1]==pf[i]){same=true; break;}
}
if(same){continue;}
if(pf.size()%2){res+=(r-1);}
else{res-=(r-1);}
}
res++; // count 1
cout << res << "\n";
return 0;
}
posted:
last update: