洛谷P4318 完全平方数(容斥,莫比乌斯反演)

传送门

求第$k$个没有完全平方数因数的数

一开始是想筛一波莫比乌斯函数,然后发现时间复杂度要炸

于是老老实实看了题解

一个数的排名$k=x-\sum_{i=1}^{x}{(1-|\mu(i)|)}$

因为$k$是不降的,所以我们可以考虑二分

那么如何计算区间$[1,x]$的无完全平方数因数的数的个数嘞?

我们可以考虑计算有平方因数的数的个数再减掉就可以了

那么这个可以用一个容斥计算,就是0个完全平方数因数的个数(即1的倍数)-1个完全平方数因数个数(即4,9,16...的倍数)+2个...

然后不难发现这个容斥里每一项的系数是$\mu(i)$(别问我我也不知道)

然后带进去瞎搞就好了

 1 //minamoto
 2 #include<iostream>
 3 #include<cstdio>
 4 #include<cmath>
 5 using namespace std;
 6 #define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
 7 char buf[1<<21],*p1=buf,*p2=buf;
 8 inline int read(){
 9     #define num ch-'0'
10     char ch;bool flag=0;int res;
11     while(!isdigit(ch=getc()))
12     (ch=='-')&&(flag=true);
13     for(res=num;isdigit(ch=getc());res=res*10+num);
14     (flag)&&(res=-res);
15     #undef num
16     return res;
17 }
18 const int N=5e4+5;
19 int vis[N],p[N],mu[N],m;
20 void init(){
21     mu[1]=1;
22     for(int i=2;i<=50000;++i){
23         if(!vis[i]) p[++m]=i,mu[i]=-1;
24         for(int j=1;j<=m&&i*p[j]<=50000;++j){
25             vis[i*p[j]]=1;
26             if(i%p[j]==0) break;
27             mu[i*p[j]]=-mu[i];
28         }
29     }
30 }
31 inline int work(int k){
32     int res=0,lim=sqrt(k);
33     for(int i=1;i<=lim;++i)
34     res+=mu[i]*(k/i/i);
35     return res;
36 }
37 int main(){
38 //    freopen("testdata.in","r",stdin);
39     init();
40     int T=read();
41     while(T--){
42         int k=read();
43         int l=1,r=2e9,ans;
44         while(l<=r){
45             int mid=(1ll*l+r)>>1,x=work(mid);
46             if(x>=k) ans=mid,r=mid-1;
47             else l=mid+1;
48         }
49         printf("%d\n",ans);
50     }
51     return 0;
52 }

猜你喜欢

转载自www.cnblogs.com/bztMinamoto/p/9700893.html