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

Description

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

 

Solution

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

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

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

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

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

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

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

  有 于是二分上限2*k

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

 

Code

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

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

  

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<cstring>
 4 #include<cmath>
 5 using namespace std;
 6 const int maxn=5e4+5;
 7 
 8 int mu[maxn],flag[maxn];
 9 int prime[maxn],cnt;
10 
11 int getmu(){
12     mu[1]=1;
13     for(int i=2;i<maxn;i++){
14         if(!flag[i]){
15             prime[++cnt]=i;
16             mu[i]=-1;
17         }
18         for(int j=1;i*prime[j]<maxn&&j<=cnt;j++){
19             flag[i*prime[j]]=1;
20             if(i%prime[j]==0){
21                 mu[i*prime[j]]=0;
22                 break;
23             }
24             mu[i*prime[j]]=-mu[i];
25         }
26     }
27 }
28 
29 int work(int n){
30     int ret=0;
31     for(int i=1;i*i<=n;i++)
32         ret+=mu[i]*int(1.0*n/(i*i));
33     return ret;
34 }
35 
36 int main(){
37     int T,k;
38     scanf("%d",&T);
39     getmu();
40     
41     while(T--){
42         scanf("%d",&k);
43         int l=1,r=2*k;
44         while(l<r){
45             int mid=(l>>1)+(r>>1)+(l&r&1);
46             if(work(mid)>=k) r=mid;
47             else l=mid+1;
48         }
49         printf("%d\n",l);
50     }
51     return 0;
52 }

 

posted @ 2015-06-23 16:59  CyanNode  阅读(169)  评论(0编辑  收藏  举报