洛谷 P4318 完全平方数 二分+容斥

首先我们可以二分答案。然后转变为判断 \(mid\) 以内不讨厌的数和 \(k\) 的关系。

\(mid\) 以内不讨厌的数= \(mid\) \(-\) \(mid\) 以内讨厌的数

对于讨厌的数我们可以枚举 \(i\),看 \(i^2\) 会造成多少个讨厌的数,显然是 \(\displaystyle \left \lfloor \frac{n}{i^2} \right \rfloor\)

然后我们发现会有重复枚举的(像 \(36\) 会被 \(2,3,6\) 都枚举到),需要乘上一个容斥系数 \(f[i]\).

\(f[i]\) 取决于 \(i\) 有多少个质因数,奇数个为 \(1\) ,偶数个为 \(-1\)

这很好理解,比如一个数 \(n\) ,会被有一个质因数的 \(i\) 枚举的时候加上,被有偶数个质因数的 \(i\) 枚举的时候会发现减多了,枚举有 \(3\) 个质因数的 \(i\) 时还得加回来...

#include<iostream>
#include<cstdio>
#define LL long long
using namespace std;
int T, tot;
LL n, k, ans, l, r, mid;
int zhi[100010], f[100010], vis[100010];
void YYCH()
{
	for (int i = 2; i <= 100000; ++i)
	{
		if (!vis[i])zhi[++tot] = i;
		for (int j = 1; j <= tot && i * zhi[j] <= 100000; ++j)
		{
			vis[i * zhi[j]] = 1;
			if (!(i % zhi[j]))break;
		}
	}
}
void dfs(int x, int beg, int js)
{
	f[x] = js & 1 ? 1 : -1; long long y;
	for (int i = beg; i <= tot; ++i)
	{
		if ((y = (long long)x * zhi[i]) > 100000)break;
		dfs(y, i + 1, js + 1);
	}
}
int check(LL n)
{
	LL res = 0;
	for (int i = 2; (LL)i * i <= n; ++i)
		if (f[i])res += f[i] * n / ((LL)i * i);
	return n - res;
}
signed main()
{
	YYCH(); dfs(1, 1, 0);
	cin >> T;
	while (T--)
	{
		scanf("%lld", &k); l = 1; r = k << 1;
		while (l <= r)
		{
			mid = (l + r) >> 1;
			if (check(mid) >= k)r = mid - 1, ans = mid;
			else l = mid + 1;
		}
		printf("%lld\n", ans);
	}
	return 0;
}

猜你喜欢

转载自www.cnblogs.com/wljss/p/12659072.html