完全平方数(莫比乌斯函数容斥)
小 X 自幼就很喜欢数。但奇怪的是,他十分讨厌完全平方数。他觉得这些数看起来很令人难受。由此,他也讨厌所有是完全平方数的正整数倍的数。然而这丝毫不影响他对其他数的热爱。
这天是小X的生日,小 W 想送一个数给他作为生日礼物。当然他不能送一个小X讨厌的数。他列出了所有小X不讨厌的数,然后选取了第 K个数送给了小X。小X很开心地收下了。
然而现在小 W 却记不起送给小X的是哪个数了。你能帮他一下吗?
Solution
首先可以在外层套上二分答案把问题转化为判定问题。
问题变成了在1~x中,是否存在mid个数不是完全平方数。
根据容斥原理,答案就是:0个质数乘积的平方的倍数的数量(1的倍数)- 1个质数乘积的平方的倍数的数量(4,9,25的倍数)+ 2个质数乘积的平方的倍数的数量(36,100的倍数)。
再来分析一波莫比乌斯函数,当i中存在完全平方数时,miu[i]=0,有奇数个质因子时我们应当减一,有偶数个质因子时就加。
所以我们枚举i,容斥系数就是miu[i].
Code
#include<iostream> #include<cstdio> #include<cmath> #define N 300009 using namespace std; long long miu[N],div[N],prime[N],n,t; inline void kk() { miu[1]=1; for(int i=2;i<=N;++i) { if(!div[i]) { prime[++prime[0]]=i; miu[i]=-1; } for(int j=1;j<=prime[0]&&prime[j]*i<=N;++j) { div[prime[j]*i]=1; if(i%prime[j]==0) {miu[i*prime[j]]=0;break;} else miu[i*prime[j]]=-miu[i]; } } } long long find(long long x) { long long ll=sqrt(x),ans=0; for(int i=1;i<=ll;++i) ans+=miu[i]*x/(i*i); return ans; } long long work(long long x) { long long l=1,r=x<<1,ans=0; while(l<=r) { int mid=(l+r)>>1; if(find(mid)<x)l=mid+1; else { ans=mid;r=mid-1; } } return ans; } int main() { cin>>t; kk(); while(t--) { scanf("%lld",&n); printf("%lld\n",work(n)); } return 0; }