![](https://i-blog.csdnimg.cn/blog_migrate/a83f62b14112b849947efce44ce4474a.png)
![](https://i-blog.csdnimg.cn/blog_migrate/e7b3c92d07762f5244f9f243d96648f9.png)
![](https://i-blog.csdnimg.cn/blog_migrate/9a7c36b0855db584ab1ff75e58cd3a11.png)
#include <iostream>
using namespace std;
int a[50000000]; // 0朝上 1朝下
int main()
{
int n, ans = 0;
cin >> n;
a[1] = 1; // 第1个硬币朝下
for (int i = 1; i <= n; i++)
{
if (a[i] == 0)
continue; // 硬币i朝上 跳过
ans++; // 硬币i朝下 翻转1次
for (int j = i; j <= n; j += i)
{
if (a[j] == 0)
a[j] = 1;
else
a[j] = 0; // 硬币i的所有倍数j都翻转
}
}
cout << ans;
return 0;
}
![](https://i-blog.csdnimg.cn/blog_migrate/649e1e1a56372eda98ca315f3a3c5bdb.png)
![](https://i-blog.csdnimg.cn/blog_migrate/9371625b633ef611ad080683371fd2de.png)
![](https://i-blog.csdnimg.cn/blog_migrate/178af298ed5b1a913c2d3cb1b6559cd4.png)
![](https://i-blog.csdnimg.cn/blog_migrate/d49c7e200237ed9e4a7d763a89eee440.png)
#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; // 初始化莫比乌斯函数值为1
for (int i = 2; i <= n; i++) {
if (!st[i]) { // 如果i是质数
primes[cnt++] = i; // 将i存入质数数组
mu[i] = -1; // 设置莫比乌斯函数值为-1
}
for (int j = 0; j < cnt && primes[j] * i <= n; j++) { // 遍历已知质数,计算i的质因数
int x = primes[j];
st[i * x] = true; // 标记i*x为合数
if (i % x == 0) { // 如果i可以被x整除,说明x是i的一个质因数
break;
} else {
mu[i * x] = -mu[i]; // 否则,根据莫比乌斯函数的性质,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]; // 如果n小于等于20000000,直接返回对应的莫比乌斯函数值
if (ans_mu.count(n)) return ans_mu[n]; // 如果已经计算过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; // 输入硬币数量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;
}