AcWing
  • 首页
  • 活动
  • 题库
  • 竞赛
  • 应用
  • 更多
    • 题解
    • 分享
    • 商店
    • 问答
    • 吐槽
  • App
  • 登录/注册

AcWing 5003. 翻转硬币    原题链接    困难

作者: 作者的头像   呼呼喵 ,  2023-05-09 17:42:04 ,  所有人可见 ,  阅读 153


2


首先对一个数操作两次等于没有操作,所以每个数要么操作要么不操作。

首先$1$和所有质数显然一定要操作。

对于$x=p_1p_2$,之前已经被翻转过$3$次,所以一定要操作。

对于$x=p_1p_2p_3$,之前已经被翻转过$7$次,所以一定要操作。

…

对于$x = p_1p_2 …p_k$,之前已经被翻转过$2^k-1$次,所以一定要操作。

这样操作之后所有$x = p_1^{\alpha_1}p_2^{\alpha_2} …p_k^{\alpha_k}$都被翻转了$2^k$次,满足要求。

答案就是$\sum\limits _{i=1}^n \mu^2(i)$。

$\sum\limits_{i=1} ^ {n} \mu^2(i) = \sum\limits_{i=1} ^{\lfloor \sqrt n \rfloor} \mu(i) \lfloor \frac{n}{i^2} \rfloor$

杜教筛+整除分块即可。

时间复杂度不会算,反正过了。

#include <iostream>
#include <unordered_map>
#include <cmath>

using namespace std;

const int N = 20000010;

using i64 = long long;

int primes[N], cnt;
bool st[N];
int mu[N];
unordered_map<int, int> ans_mu;

void init(int n) {
    mu[1] = 1;
    for (int i = 2; i <= n; i++) {
        if (!st[i]) {
            primes[cnt++] = i;
            mu[i] = -1;
        }
        for (int j = 0; j < cnt && primes[j] * i <= n; j++) {
            int x = primes[j];
            st[i * x] = true;
            if (i % x == 0) {
                break;
            } else {
                mu[i * x] = -mu[i];
            }
        }
    }
    for (int i = 1; i <= n; i++) mu[i] += mu[i - 1];
}

int sum_mu(int n) {
    if (n <= 20000000) return mu[n];
    if (ans_mu.count(n)) return ans_mu[n];
    i64 res = 1;
    for (i64 l = 2, r; l <= n; l = r + 1) {
        r = n / (n / l);
        res -= (r - l + 1) * sum_mu(n / l);
    }
    return ans_mu[n] = res;
}

int main() {
    init(20000000);
    i64 n;
    cin >> n;
    i64 res = 0;
    for (i64 l = 1, r; l <= n / l; l = r + 1) { 
        r = sqrt(n / (n / l / l));
        res += (sum_mu(r) - sum_mu(l - 1)) * (n / (l * l));
    }
    cout << res << '\n';
    return 0;
}

0 评论

你确定删除吗?

© 2018-2023 AcWing 版权所有  |  京ICP备17053197号-1
用户协议  |  隐私政策  |  常见问题  |  联系我们
AcWing
请输入登录信息
更多登录方式: 微信图标 qq图标 qq图标
请输入绑定的邮箱地址
请输入注册信息