bzoj 2440 (莫比乌斯函数)

时间:2023-03-10 06:31:05
bzoj 2440 (莫比乌斯函数)

bzoj 2440 完全平方数

题意:找出第k个不是完全平方数的正整数倍的数。

例如 4  9  16  25 36什么的
通过容斥原理,我们减去所有完全数  4有n/4个,但是36这种会被重复减去,
所有我们还需要加上类似36的数,然后你会发现这些数前面的符号和他们开根号的
莫比乌斯函数一样
数据很大有1e9,如果先进行预处理再从头到尾找感觉不现实,考虑使用二分,枚举mid,
然后每次查找1到mid中不是完全平方数的正整数倍的数的个数

Orz:机制的二分使用

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <queue>
#include <vector>
#include <algorithm>
#include <functional>
typedef long long ll;
using namespace std; const int inf = 0x3f3f3f3f;
const int maxn = 1e5;
int tot;
int is_prime[maxn];
int mu[maxn];
int prime[maxn]; void Moblus()
{
tot = 0;
mu[1] = 1;
for(int i = 2; i < maxn; i++)
{
if(!is_prime[i])
{
prime[tot++] = i;
mu[i] = -1;
} for(int j = 0; j < tot && i*prime[j] < maxn; j++)
{
is_prime[i*prime[j]] = 1;
if(i % prime[j])
{
mu[i*prime[j]] = -mu[i];
}
else
{
mu[i*prime[j]] = 0;
break;
}
}
} } ll get_(ll mid)
{
ll num = 0;
for(int i = 1; i*i <= mid; i++)
{
num += (ll)mu[i]*(mid/(i*i));
}
return num;
} int main()
{
int T;
Moblus();
scanf("%d",&T);
while(T--)
{
ll k;
scanf("%lld",&k);
ll l = 1;
ll r = 2*k+1;
while(l <= r)
{
ll mid = (l+r)>>1;
ll num = get_(mid);
if(num < k)
l = mid + 1;
else
r = mid - 1;
}
printf("%lld\n",l);
}
}