【洛谷P4318】完全平方数

题目

题目链接: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;
}
posted @ 2020-09-24 17:44  stoorz  阅读(180)  评论(0编辑  收藏  举报