Bzoj 2440. [中山市选2011]完全平方数

题目大意:

题目链接
给定 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| A1A2...Am就代表这些质数所表示的平方的乘积的集合的个数

所以集合 ∣ M ∣ = N − ∣ A 1 ∩ A 2 ∩ . . . ∩ A m ∣ |M|=N-|A_1\cap A_2 \cap ... \cap A_m| M=NA1A2...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 1N 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=N0i2Ni2Ni=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;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值