首先,我们肯定要用到二分答案。
这道题目就是统计第k个μ不是0的数,线性筛显然会炸飞的,但当二分出一个数而统计有多少个小于等于他的合法数时,就可以容斥一下,即:1^2的倍数都不合法,2^2的倍数都不合法……4^2的倍数已经通过2^2统计过且没有重复……6^2的倍数被3^2的倍数和2^2的倍数重复统计因此要加上……
对于如上过程,我们可以简化成一个公式:$\sum_{i=1}^{\sqrt{k}}\mu(i)\cdot k/i^{2}$,而i的范围是$\sqrt{k}=40000$,再乘上二分的$o(log_{2}n)$就可以过掉了(当然还可以对i进行数论分块,使得i的范围为200,但实际并不需要)。
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define ll long long 4 #define N 100005 5 ll t,n,l,r,mid,ans,mu[N],vis[N],p[N]; 6 void mobies(int n){ 7 mu[1]=1; 8 for(int i=2;i<=n;i++){ 9 if (!vis[i])mu[p[++p[0]]=i]=-1; 10 for(int j=1;j<=p[0];j++){ 11 if (p[j]*i>n)break; 12 vis[i*p[j]]=1; 13 if (i%p[j]==0)break; 14 mu[i*p[j]]=-mu[i]; 15 } 16 } 17 } 18 ll calc(ll n){ 19 ll ans=0; 20 for(ll i=1;i*i<=n;i++)ans+=n/(i*i)*mu[i]; 21 return ans; 22 } 23 int main(){ 24 scanf("%lld",&t); 25 mobies(N-5); 26 while (t--){ 27 scanf("%lld",&n); 28 for(l=1,r=(n<<1),mid=n;l<r;mid=(l+r>>1)) 29 if (calc(mid)<n)l=mid+1; 30 else r=mid; 31 printf("%lld\n",l); 32 } 33 }