【二分+容斥+莫比乌斯反演】BZOJ2440 完全平方数

时间:2023-01-26 07:54:49

Description

  求第k个没有完全平方因子的数,k<=1e9。

Solution

  这其实就是要求第k个µ[i](莫比乌斯函数)不为0的数。

  然而k太大数组开不下来是吧,于是这么处理。

  二分答案x,问题转化为求[1,x]间有多少个没有完全平方因子的数。

  容斥,加上全部,减去一个质数的平方的倍数个数,加上两个质数乘积的平方的倍数个数...

  然后发现,每个数的系数就是µ

  这也说明了莫比乌斯的原理就是容斥,µ函数就是容斥系数

  具体来说,对于每一个i<=sqrt(x),对于ans的贡献就是µ[i]*int(n/(i*i))(向下取整)

  有【二分+容斥+莫比乌斯反演】BZOJ2440 完全平方数 于是二分上限2*k

  复杂度为log(n)*sqrt(n)

Code

  一开始直接mid=(l+r)>>1溢出T了一发

  正确姿势mid=l>>1+r>>1+(l&r&1)

  

 #include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
const int maxn=5e4+; int mu[maxn],flag[maxn];
int prime[maxn],cnt; int getmu(){
mu[]=;
for(int i=;i<maxn;i++){
if(!flag[i]){
prime[++cnt]=i;
mu[i]=-;
}
for(int j=;i*prime[j]<maxn&&j<=cnt;j++){
flag[i*prime[j]]=;
if(i%prime[j]==){
mu[i*prime[j]]=;
break;
}
mu[i*prime[j]]=-mu[i];
}
}
} int work(int n){
int ret=;
for(int i=;i*i<=n;i++)
ret+=mu[i]*int(1.0*n/(i*i));
return ret;
} int main(){
int T,k;
scanf("%d",&T);
getmu(); while(T--){
scanf("%d",&k);
int l=,r=*k;
while(l<r){
int mid=(l>>)+(r>>)+(l&r&);
if(work(mid)>=k) r=mid;
else l=mid+;
}
printf("%d\n",l);
}
return ;
}