【BZOJ2440】[中山市选2011]完全平方数
题意描述
原题
一句话描述:
求第K个不是完全平方数的倍数的数。
K≤$10^{9}$
------------------------------------------
题解:
首先,直接求第$k$个不是完全平方数倍数的数不好求,我们不妨将它转换为一个判定问题:对于一个确定的常数$x$,他是不是第k个不是完全平方数倍数的数。这句话等价于:$[1,x]$是否有k个不是完全平方数倍数的数,这个怎么求呢?
根据容斥原理,答案就是:0个质数乘积的平方的倍数的数量(1的倍数)- 1个质数乘积的平方的倍数的数量(4,9,25的倍数)+ 2个质数乘积的平方的倍数的数量(36,100的倍数)。
恰好发现,$i^2$对应的符号就是$μ(i)$,所以答案就是
那么我们二分一下$x$,就能找到答案了。二分的范围是$[1,k*2]$.
代码实现:
#include<cstdio> #include<cmath> #include<cstring> #include<algorithm> const int maxn = 1e6+10; typedef long long ll; int mu[maxn],prime[maxn],vis[maxn]; void init_mu(int n){ int cnt=0; mu[1]=1; for(int i=2;i<n;i++){ if(!vis[i]){ prime[cnt++]=i; mu[i]=-1; } for(int j=0;j<cnt&&i*prime[j]<n;j++){ vis[i*prime[j]]=1; if(i%prime[j]==0) {mu[i*prime[j]]=0;break;} else { mu[i*prime[j]]=-mu[i];} } } } inline ll find(ll x) { ll least = sqrt(x+0.5),ans=0; for(register int i=1;i<=least;i++) { ans+=mu[i]*x/(1LL*i*i); } return ans; } inline ll calc(ll k) { ll l = 1,r = k<<1; while(l<r) { ll mid = (r+l)>>1; ll temp = find(mid); #ifdef DEBUG printf("%d %d %d\n",l,r,temp); #endif if(temp<k) l=mid+1; else r=mid; } return r; } int T; ll k; int main() { init_mu(1000001); scanf("%d",&T); while(T--) { scanf("%lld",&k); printf("%lld\n",calc(k)); } return 0; }