题目
题目链接:https://www.luogu.com.cn/problem/P4318
小 X 自幼就很喜欢数。但奇怪的是,他十分讨厌完全平方数。他觉得这些数看起来很令人难受。由此,他也讨厌所有是完全平方数的正整数倍的数。然而这丝毫不影响他对其他数的热爱。
这天是小 X 的生日,小 W 想送一个数给他作为生日礼物。当然他不能送一个小 X 讨厌的数。他列出了所有小 X 不讨厌的数,然后选取了第 \(k\) 个数送给了小X。小 X 很开心地收下了。
然而现在小 W 却记不起送给小 X 的是哪个数了。你能帮他一下吗?
思路
即求第 \(k\) 个不含完全平方数因子的数字。
二分转换为判定性问题,转化成求不超过 \(n\) 有多少个不含完全平方因子的数。
设 \(f(i)\) 表示 \(i\) 个不同质数的乘积的平方的数字个数,那么答案为 \(\sum^{\sqrt{n}}_{i=1}(-1)^{i+1}f(i)\)。
发现系数即为 \(\mu(i)\)。所以线性筛出 \(\mu\) 即可。
时间复杂度 \(O(T\log A\sqrt{A})\)。其中 \(A\) 为二分上界。
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1000010;
int Q,n,m,prm[N],mu[N];
bool v[N];
void findprm(int n)
{
mu[1]=1;
for (int i=2;i<=n;i++)
{
if (!v[i])
{
prm[++m]=i;
mu[i]=-1;
}
for (int j=1;j<=m;j++)
{
if (i>n/prm[j]) break;
v[i*prm[j]]=1; mu[i*prm[j]]=-mu[i];
if (!(i%prm[j]))
{
mu[i*prm[j]]=0;
break;
}
}
}
}
ll count(ll mid)
{
ll cnt=0;
for (int i=1;1LL*i*i<=mid;i++)
cnt+=mid/i/i*mu[i];
return cnt;
}
int main()
{
findprm(N-10);
scanf("%d",&Q);
while (Q--)
{
scanf("%d",&n);
ll l=1,r=10000000000LL,mid;
while (l<=r)
{
mid=(l+r)>>1;
if (count(mid)>=n) r=mid-1;
else l=mid+1;
}
printf("%lld\n",r+1);
}
return 0;
}