题目

定义一个数 x 的价值为:将这个数分解成若干个正整数 a1,a2,,akk 是任意可行正整数)的乘积形式x=a1×a2××akai 只能有一个质因子,且对于  ij,都满足 gcd(ai,aj)=1,即两个数互质。

分解之后,这些正整数的和 ai 就是这个数的价值。特殊定义:1 的价值是 0

多组询问,每次给定正整数 L,R,求大小在 LR 范围内的所有数的价值之和。

限制:

  • 1T104
  • 1LR3×107

算法分析

做法:欧拉筛

使用 ps 数组记录当前已经筛出的质数,使用 val[x] 记录 x 的价值

原理:欧拉筛中通过 if (i%ps[j] == 0) break; 控制每个合数只能被它的最小质因子标记,使得使得时间复杂度达到线性。

对于质数 ival[i] = i
对于合数 i*ps[j] 有两种情况:

  • i 的最小质因子大于 ps[j],那么 val[i*ps[j]] = val[i] + ps[j]
  • i 的最小质因子等于 ps[j],那么先分解出 i 里面 ps[j] 的最大次幂因子 x,那么 val[i*ps[j]] = val[i] - x + ps[j]*x

然后通过前缀和预处理,每次询问做差分即可。

代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
using ll = long long;
const int MX = 3e7+5;
int ps[MX/10], pf[MX];
ll val[MX];
void init() {
int c = 0;
for (int i = 2; i < MX; ++i) {
if (!pf[i]) ps[++c] = i, pf[i] = i, val[i] = i;
for (int j = 1; i*ps[j] < MX; ++j) {
if (i%ps[j] == 0) {
pf[i*ps[j]] = pf[i]*ps[j];
val[i*ps[j]] = val[i] - pf[i] + pf[i*ps[j]];
break;
}
else {
pf[i*ps[j]] = ps[j];
val[i*ps[j]] = val[i] + ps[j];
}
}
}
for (int i = 1; i < MX; ++i) val[i] += val[i-1];
}
int main() {
freopen("stupid.in", "r", stdin);
freopen("stupid.out", "w", stdout);
init();
int t;
cin >> t;
while (t--) {
int l, r;
cin >> l >> r;
--l;
cout << val[r]-val[l] << '\n';
}
return 0;
}