Step1 Problem:
找 2 到 n 中满足条件 x 的个数。
条件:x 唯一分解后质因数的幂的 gcd = 1。
例:10:4, 8, 9 不满足条件,输出 6.
数据范围:
1<=T<=1e5, 2 <= n <= 1e18.
Step2 Ideas:
x^4 * y^2 = (x^2 * y)^2,也就是对幂进行提公因式。
幂提公因式 = 1 的个数就是结果。
枚举:
在范围内:t^1 有 g1 个 t
在范围内:t^2 有 g2 个 t
在范围内:t^3 有 g3 个 t
在范围内:t^4 有 g4 个 t
在范围内:t^5 有 g5 个 t
… … … … … … … … …
结果 += sum{g(i) * mbus(i)}, 1 <= i <= 62.
Step3 Code:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N = 100;
int prim[N], cnt;
int mbus[N], vis[N];
void get_mbus()
{
memset(vis, 0, sizeof(vis));
memset(mbus, 0, sizeof(mbus));
vis[0] = vis[1] = 1; mbus[1] = 1;
cnt = 0;
for(int i = 2; i < N; i++)
{
if(!vis[i]) {
prim[cnt++] = i;
mbus[i] = -1;//奇数个质因子
}
for(int j = 0; i*prim[j] < N && j < cnt; j++)
{
vis[i*prim[j]] = 1;
if(i%prim[j] == 0) {
mbus[i*prim[j]] = 0;//存在质因子有平方
break;
}
else {
mbus[i*prim[j]] = -1*mbus[i];//积性函数,质因子多了一个所以乘 -1.
}
}
}
}
//ll gen(ll n, ll k) {
// ll t = powl(n, 1.0/k);
// return t+(powl(t+1, k) <= n);
//}
ll gen(ll n, ll k) {
ll t = powl(n, 1.0/k)-0.5;
return t+(powl(t+1, k)-0.5 <= n);
}
int main()
{
get_mbus();
int T;
ll n;
scanf("%d", &T);
while(T--)
{
scanf("%lld", &n);
ll ans = n-1;
for(int i = 2; i < 100; i++)
{
if(mbus[i] == 0) continue;
ll x = gen(n, i);
if(x == 1) break;
ans += mbus[i] * (x-1);
}
printf("%lld\n", ans);
}
return 0;
}