设 f ( n ) f(n) f(n)表示在 1 1 1到 n n n中小X不讨厌的数的数量。显然 f ( n ) f(n) f(n)是单调递增的,所以我们可以二分答案。
根据容斥原理可得
f ( n ) = n f(n)=n f(n)=n以内所有数的数量 − n -n −n以内每个质数的平方的倍数的数量 + n +n +n以内每两个质数的平方的倍数的数量 − ⋯ -\cdots −⋯
我们发现每个部分的正负与莫比乌斯函数有关系,可变为
f ( n ) = ∑ i = 1 n μ ( i ) × ⌊ n i 2 ⌋ f(n)=\sum\limits_{i=1}^{\sqrt n}\mu(i)\times \lfloor \dfrac{n}{i^2}\rfloor f(n)=i=1∑nμ(i)×⌊i2n⌋
二分求得使 f ( n ) = k f(n)=k f(n)=k的 n n n值即可。时间复杂度为 O ( T w log w ) O(T\sqrt w\log w) O(Twlogw),其中 w w w为二分的范围。
code
#include<bits/stdc++.h>
using namespace std;
int t,k,z[100005],p[100005],mu[100005];
long long check(long long g){
long long re=0;
for(int i=1;i*i<=g;i++){
re=re+mu[i]*(g/i/i);
}
return re;
}
int main()
{
mu[1]=1;
for(int i=2;i<=100000;i++){
if(!z[i]){
p[++p[0]]=i;mu[i]=-1;
}
for(int j=1;j<=p[0]&&i*p[j]<=100000;j++){
z[i*p[j]]=1;
if(i%p[j]==0){
mu[i*p[j]]=0;
break;
}
mu[i*p[j]]=-mu[i];
}
}
scanf("%d",&t);
while(t--){
scanf("%d",&k);
long long l=1,r=2e9,mid,vt;
while(l<=r){
mid=(l+r)/2;
vt=check(mid);
if(vt<k) l=mid+1;
else r=mid-1;
}
printf("%lld\n",r+1);
}
return 0;
}