解説:#14 Xth root
製作者:QCFium
## 解説
まず$\sqrt[x]{N}$が整数になるような整数$x$としては$1$~$63$が考えられます。(2でも64したら$10^{18}$を超えてしまうので)
$x = 1$~$63$それぞれについて$\sqrt[x]{N}$が整数になるかを判定します。
$x \ge 3$については簡単です。$\sqrt[x]{N} \le 10^6$なので$\sqrt[x]{N}$を全探索し、何乗かして$N$になるかを調べれば$O(N^{\frac{1}{3}} \log N)$で全部判定できます。
問題は$x = 2$です。つまり$N$が平方数かを判定しなければなりません。もちろん$\sqrt{N}$のオーダーかけていては多分間に合いません。
標準ライブラリにあるsqrt関数は平方根を求めることができます。戻り値は浮動小数点型なので切り捨てして整数にしてこの値を$a$とすると、$a^2=N$または$(a+1)^2=N \iff N$が平方数です。($(a + 1)^2$があるのは浮動小数点の誤差で$\sqrt{100}=9.9999999$->切り捨てで$a=9$みたいになる可能性が否定できないからです。
sqrt関数の計算量は不明ですが速そうなので通ります。
計算量保証がほしい場合は、$N$から$a$を求めるのに二分探索を使うことができます。任意の$b>0$について$b < \sqrt{N} \iff b^2 \lt N$だから$b$が$a$より小さいか大きいかは簡単に判定できるため二分探索で$a$を求めることができます。
実装例は以下の通りです。
```
#include <bits/stdc++.h>
int main() {
long long n;
scanf("%lld", &n);
int res = 1;
for (int i = 2; i <= 1000000; i++) {
int64_t cur = i;
int cnt = 1;
while (cur != n) {
if ((uint64_t) cur * (uint32_t) i / (uint32_t) i != (uint64_t) cur) break; // オーバーフロー対策
cur *= i;
cnt++;
}
if (cur == n) res = std::max(res, cnt);
}
int sq = sqrt(n);
if ((int64_t) sq * sq == n || (int64_t) (sq + 1) * (sq + 1) == n) res = std::max(res, 2);
printf("%d\n", res);
return 0;
}
```