题意
计算,
表示在
范围内
的个数
数据范围:
题解
这里介绍容斥和莫比乌斯反演两种方法(如果想系统了解这种题目的各种大体思路可以看两两gcd求和的4种方法)
下面先设分别为
为
倍数和等于
的个数,有
容斥(筛法)
容斥是利用先计算到每个
,再通过从后向前处理得到每个
最后针对问题选取需要的求解
for(i = 1; i <= top; i++) F[i] = (LL)(N / i) * (M / i);
for(i = top; i >= 1; i--){
f[i] = F[i];
for(j = i * 2; j <= top; j += i)
f[i] -= f[j];
}
莫比乌斯反演
由莫比乌斯反演知:
问题的
这里如果是单次询问可以不进一步化解直接求和,时间复杂度为
for(i = 1; i <= top; i++) pre[i] = pre[i - 1] + mu[i];
for(i = 1; i <= top; i++) sum[i] = sum[i - 1] + (2 * i - 1);
int l, r; LL ans = 0;
for(l = 1; l <= top; l = r + 1){
r = min(N / (N / l), M / (M / l));
ans += (LL)solve(N / l, M / l) * (sum[r] - sum[l - 1]);
}
若进一步化解
这种化解一般都额外需要一个的前缀和(不化解为
),而每次计算只需要
,一般针对多次询问
for(i = 1; i <= top; i++)
for(j = i; j <= top; j += i)
sum[j] += mu[j / i] * (2 * i - 1);
for(i = 1; i <= top; i++) sum[i] += sum[i - 1];
int l, r; LL ans = 0;
for(l = 1; l <= top; l = r + 1){
r = min(N / (N / l), M / (M / l));
ans += (LL)(N / l) * (M / l) * (sum[r] - sum[l - 1]);
}