You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

61 lines
2.3 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#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;
}
}