题目链接:https://codeforces.com/contest/1036/problem/F
如果分解后的质因子个数的 (gcd) 不为 (1),那原数是 (n) 开方,枚举开方数按莫比乌斯函数容斥,注意 (pow) 函数的精度问题,可以先调高上界然后向下调整精度
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 105;
int T;
ll n;
int cnt;
int prime[1010], mu[1010], is_prime[1010];
ll qsm(ll i, ll po){
ll res = 1ll;
while(po){
if(po & 1) { // 防止乘爆
if(res >= 2e18/i) return 2e18+7;
res = res * i;
}
if(po > 1){
if(i >= 2e18/i) return 2e18+7;
i = i * i;
}
po >>= 1;
}
return res;
}
int calc(int x){
int l = max(1, (int)pow(n, 1.0/x)-3), r = (int)pow(n, 1.0/x)+3;
int res = 0;
while(l <= r){
int mid = (l + r) / 2;
if(qsm(mid, x) <= n){
res = mid;
l = mid + 1;
} else{
r = mid - 1;
}
}
return res - 1;
}
int main(){
mu[1] = 1;
for(int i = 2; i <= 100; ++i){
if(!is_prime[i]){
prime[++cnt] = i;
mu[i] = -1;
}
for(int j = 1 ; j <= cnt && prime[j] * i <= 100 ; ++j){
is_prime[i * prime[j]] = 1;
if(i % prime[j] == 0) {
mu[i * prime[j]] = 0;
break;
} else {
mu[i * prime[j]] = -mu[i];
}
}
}
scanf("%d", &T);
while(T--){
scanf("%lld", &n);
ll ans = n-1;
for(int i = 2 ; (1ll<<i) <= n ; ++i){
if(mu[i] == 0) continue;
ans += 1ll * mu[i] * calc(i);
}
printf("%lld
", ans);
}
return 0;
}