题目大意:
题目链接
给定
k
k
k,找寻一个集合
M
M
M中第
k
k
k个数是什么,该集合不含完全平方数(不考虑1)以及其倍数
解题思路:
将 N N N以内每个质数都列举出来集合为 P P P
根据容斥公式:
设
A
i
A_i
Ai代表第i个质数
p
i
p_i
pi,
p
i
2
p_i^2
pi2的一切与正整数乘积的集合
∣
A
1
∩
A
2
∩
.
.
.
∩
A
m
∣
|A_1\cap A_2 \cap ... \cap A_m|
∣A1∩A2∩...∩Am∣就代表这些质数所表示的平方的乘积的集合的个数
所以集合 ∣ M ∣ = N − ∣ A 1 ∩ A 2 ∩ . . . ∩ A m ∣ |M|=N-|A_1\cap A_2 \cap ... \cap A_m| ∣M∣=N−∣A1∩A2∩...∩Am∣
可以发现上面的容斥式子其实就是加上奇数项,减去偶数项
那么带入 ∣ M ∣ |M| ∣M∣的表达式就是
∣ M ∣ = N − ∣ 奇 数 个 质 数 所 表 达 数 的 平 方 的 集 合 ∣ + ∣ 偶 数 个 质 数 所 表 达 数 的 平 方 的 集 合 ∣ |M|=N-|奇数个质数所表达数的平方的集合|+|偶数个质数所表达数的平方的集合| ∣M∣=N−∣奇数个质数所表达数的平方的集合∣+∣偶数个质数所表达数的平方的集合∣
而这与莫比乌斯函数
μ
(
)
\mu()
μ()又是完全对应的
N代表0个质数所表达的平方的集合,即
μ
(
1
)
∗
N
/
(
1
2
)
\mu(1)*N / (1^2)
μ(1)∗N/(12)
所以只要枚举1~N的数 ∑ i = 1 N μ ( i ) ⌊ N i 2 ⌋ \sum_{i=1}^{N}\mu(i)\left \lfloor \frac N{i^2} \right \rfloor ∑i=1Nμ(i)⌊i2N⌋
⌊
N
i
2
⌋
\left \lfloor \frac N{i^2} \right \rfloor
⌊i2N⌋代表
1
∼
N
1\sim N
1∼N中
i
2
i^2
i2的倍数有
⌊
N
i
2
⌋
\left \lfloor \frac N{i^2} \right \rfloor
⌊i2N⌋
μ
(
i
)
⌊
N
i
2
⌋
=
{
N
i
=
1
0
含
有
平
方
质
数
的
因
子
−
⌊
N
i
2
⌋
奇
数
个
不
同
的
质
因
子
⌊
N
i
2
⌋
偶
数
个
不
同
的
质
因
子
\mu(i)\left \lfloor \frac N{i^2} \right \rfloor=\left\{\begin{matrix} N & i=1 \\ 0 & 含有平方质数的因子 & \\ -\left \lfloor \frac N{i^2} \right \rfloor & 奇数个不同的质因子 \\ \left \lfloor \frac N{i^2} \right \rfloor & 偶数个不同的质因子 \end{matrix}\right.
μ(i)⌊i2N⌋=⎩⎪⎪⎨⎪⎪⎧N0−⌊i2N⌋⌊i2N⌋i=1含有平方质数的因子奇数个不同的质因子偶数个不同的质因子
还可以化简的地方是,当 i > N 时 , ⌊ N i 2 ⌋ i>\sqrt{N}时,\left \lfloor \frac N{i^2} \right \rfloor i>N时,⌊i2N⌋已经等于0
所以原式 = ∑ i = 1 N μ ( i ) ⌊ N i 2 ⌋ =\sum_{i=1}^{\sqrt{N}}\mu(i)\left \lfloor \frac N{i^2} \right \rfloor =∑i=1Nμ(i)⌊i2N⌋
ps:也可以得到一个很常用的公式:
之后因为答案具有单调性,所以二分即可,check只需 O ( n ) O(\sqrt n) O(n)
AC代码:
#include <bits/stdc++.h>
#define mod 2147483647
#define lowbit(x) (x & (-x))
using namespace std;
typedef long long ll;
const ll maxn = 2e5 + 10;
ll T, ans[maxn];
bool vis[maxn];
ll cnt, p[maxn], mu[maxn];
void init() {
mu[1] = vis[1] = 1;
for (ll i = 2; i < maxn; i++) {
if (!vis[i]) mu[i] = -1, p[++cnt] = i;
for (ll j = 1; j <= cnt && i * p[j] < maxn; j++) {
vis[i * p[j]] = 1;
if (i % p[j] == 0) {
mu[i * p[j]] = 0;
break;
}
else {
mu[i * p[j]] = -mu[i];
}
}
}
}
ll check(ll n) {
ll res = 0;
for (ll i = 1; i * i <= n; i++)
res += mu[i] * (n / (i * i));
return res;
}
ll K;
int main() {
init();
cin >> T;
while (T--) {
cin >> K;
ll lef = 1, rig = 2e10, mid = (lef + rig) >> 1, ans;
while (lef <= rig) {
ll tmp = check(mid);
if (tmp == K) ans = mid;
if (tmp >= K) rig = mid - 1;
else lef = mid + 1;
mid = (lef + rig) >> 1;
}
cout << ans << endl;
}
return 0;
}