Files
python/TangDou/Topic/Mobius/SQP4168.cpp
HuangHai 1f397eca87 'commit'
2025-08-30 18:35:01 +08:00

61 lines
2.3 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define endl "\n"
const int M = 110; // 询问次数
const int N = 10000010; // 莫比乌斯函数值的极限数据上限,sqrt(1e14)=1e7
int n, sqrtN; // T次询问,每次都是1~n,sqrtN=sqrt(max(n)),真实上限
int q[M]; // T次询问,用q数组记录下来
// 筛法求莫比乌斯函数(枚举约数)
int mu[N], sum[N]; // sum[N]:梅滕斯函数,也就是莫比乌斯函数的前缀和
int primes[N], cnt;
bool st[N];
void get_mobius(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; primes[j] <= n / i; j++) {
int t = primes[j] * i;
st[t] = true;
if (i % primes[j] == 0) {
mu[t] = 0;
break;
}
mu[t] = -mu[i];
}
}
// 维护u(x)前缀和:梅滕斯函数
for (int i = 1; i <= n; i++) sum[i] = sum[i - 1] + mu[i];
}
signed main() {
#ifndef ONLINE_JUDGE
freopen("SQP4168.in", "r", stdin);
#endif
int T;
cin >> T;
for (int i = 1; i <= T; i++) {
cin >> q[i];
n = max(n, q[i]); // 找到最大的n,这样可以避免重复计算
}
sqrtN = sqrt(n); // 最大的n,只需要枚举到sqrt(n)即可
// 对有效范围内的数字求莫比乌斯函数
get_mobius(sqrtN); // 线性求莫比乌斯函数, 前缀和
for (int i = 1; i <= T; i++) { // 离线处理,对于每个询问进行回答
n = q[i]; // 第i次的n值
int ans = 0; // 初始化返回结果
for (int l = 1, r; l <= n; l = r + 1) { // 整除分块
if (n / (l * l) == 0) break;
// n / (l * l): 分块的左边界是l,值是n/(l*l),如果n<(l*l)时,l再长大也没用,也都是0
// n/(l*l):整除分块中整个分块内的个数值,从n/(l*l)~n/(r*r)是同一个值
r = sqrt(n / (n / (l * l))); // 求出右边界r
ans += n / (l * l) * (sum[r] - sum[l - 1]); // 利用莫比乌斯函数值前缀和求块的贡献
}
cout << ans << endl;
}
}