bzoj 2440 简单莫比乌斯反演

时间:2022-01-17 14:30:41

题目大意:

找第k个非平方数,平方数定义为一个数存在一个因子可以用某个数的平方来表示

这里首先需要考虑到二分才可以接下来做

二分去查找[1 , x]区间内非平方数的个数,后面就是简单的莫比乌斯反演了

容斥原理的思想,首先考虑所有数都属于非平方数 那么就是x

然后对于每一个平方数都要减去,但是这里应该只考虑质数的平方数就可以了

那么就扩展为x - x/(2^2) - x/(3^2) - x/(k^2)....

然后因为中间存在重复减的那么要加回来

-> x - x/(2^2) - x/(3^3) - x/(k^k)+ x/(2^2*3^2)+x/(2^2*4^2)....

后面3个质因数的平方组合就是 *(-1) 了

以此类推,那么k个数组成的质因数平方就是 *(-1)^k

其实这就是一个莫比乌斯函数了

这是积性函数,用线性筛法跑一遍就行了,因为都是平方的,所以筛到不超过1000000就足够了

 #include <bits/stdc++.h>
using namespace std;
#define ll long long
#define N 100000
int mu[N+] , prime[N+] , tot;
bool check[N+];
void get_mu()
{
tot = ;
for(int i= ; i<=N ; i++){
if(!check[i]){
prime[tot++] = i;
mu[i] = -;
}
for(int j= ; j<tot ; j++){
if((ll)i*prime[j]>N) break;
check[i*prime[j]] = true;
if(i%prime[j]==){
mu[i*prime[j]] = ;
break;
}else mu[i*prime[j]] = -mu[i];
}
}
} bool ok(int m , int n)
{
int mx = (int)(sqrt(m+0.5)) , ret = m;
for(int j= ; j<=mx ; j++){
ret += m/(j*j)*mu[j];
}
return ret>=n;
} int solve(int n)
{
int l= , r=*(1e9) , ans=;
while(l<=r){
int m = ((ll)l+r)/;
// cout<<m<<endl;
if(ok(m , n)){
r=m-;
ans=m;
}
else{
l = m+;
}
}
return ans;
} int main()
{
// freopen("in.txt" , "r" , stdin);
get_mu();
int T;
scanf("%d" , &T);
while(T--){
int n;
scanf("%d" , &n);
printf("%d\n" , solve(n));
}
return ;
}