题目大意: 找到第k个无平方因子数.
看到数据范围很大, 我们要采用比\(O(n)\)还要小的做法.
考虑如果前\(x\)个数中有\(k-1\)个无平方因子数, 而前\(x+1\)个数中有\(k\)个无平方因子数, 那么\(x\)即为所求.
而由某种我不会的方式可以证明出答案是不会超过\(2n\)的, 所以我们可以二分答案.
问题就转化成了求前\(x\)个数中有多少个无平方因子数.
所以我们就要把这些无平方因子数筛一下.
那么首先所有含有平方因子的数我们都不需要考虑, 因为它们的倍数一定会被比他们小的数先筛掉.
而对于剩下的数, 为了方便描述, 我们定义\(\omega(x)\)为\(1\sim n\)中有\(x\)个不同质因子的数的个数, 即
\[
\omega(x)=\sum_{i=1,i=\prod_{i=1}^kp_i}^N[k=x]
\]
那么根据容斥, 我们就可以得到如下的式子.
\[
ans=n-\frac n{\omega(1)^2}+\frac n{\omega(2)^2}-\frac n{\omega(3)^2}+...=n-\sum_{i=1}^k{\frac n{\omega(i)^2}}*(-1)^{i+1}
\]
然后我们发现我们这个好像是莫比乌斯函数??? 恰好包含平方的数的莫比乌斯函数是0, 所以我们整合一波就可以得到
\[
ans=\sum_{i=1}^{\left \lfloor \sqrt n \right \rfloor}\mu(i)*{\left \lfloor \frac n{i^2} \right \rfloor}
\]
这样我们枚举\(i\)就可以过啦~
时间复杂度\(O(T*log_2n*\sqrt n)\)
代码:
#include <cstdio>
const int N=45005;
int pr[N],mu[N],tot,n;
bool np[N];
void shai(){
mu[1]=np[1]=1;
for(int i=2,k;i<=45000;++i){
if(!np[i]) pr[++tot]=i,mu[i]=-1;
for(int j=1;j<=tot&&(k=i*pr[j])<=45000;++j){
np[k]=1;
if(i%pr[j]==0){mu[k]=0; break;}
mu[k]=-mu[i];
}
}
}
inline bool check(int x,int s=0){
for(int i=1;i*i<=x;++i)
s+=x/(i*i)*mu[i];
return s>=n;
}
int main(){ shai();
int T; scanf("%d",&T);
while(T--){
scanf("%d",&n);
int l=1,r=n<<1;
while(l<r){
int mid=(1LL*l+r)>>1;
if(check(mid)) r=mid;
else l=mid+1;
}
printf("%d\n",r);
}
}
这个题并和莫比乌斯反演没什么关系, 算是莫比乌斯函数的一个小应用吧...