题意
设表示
的约数个数,求
组
数据范围:
题解
这个题目的关键是化解,这里有个神奇的公式
(
第一次了解到我是懵逼的 ( ′◔ ‸◔`) )
这个公式可以这么理解: 如果对于的素因子分解为
,那么
,可以看出每个素因子
作用是独立的
假设x,y的素因子分解中的次数为分别为
.
对于
的贡献为
在中只考虑
只当
在
中出现
中不出现的
种,
中不出现
中出现的
种, 都不出现的
种,所以贡献为
,等式成立
那么原来要求的式子变为 ,这里可以看到
可以转换为约数的贡献
以中约数作为枚举项, 式子变为
(
相当于上式
,不过是整体考虑每个
贡献)
对于这个式子如果做过相关题目那就很熟悉了求两两gcd和的不同思路
设(
条件比
更松,也更易求)
就有,由莫比乌斯反演
那么问题就变为如何求解注意到对于
,如果
那么就有贡献
考虑的约数
.以
作为枚举项,有
(这里
独立,可以通过处理前缀和
求出)
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
using LL = long long;
const int MAXN = 5e4 + 5;
int T, N, M;
bool noprime[MAXN];
int prime[MAXN], cnt_p, mu[MAXN];
int pre[MAXN], sum[MAXN];
void Euler_Sieve(int top);
int main(){
ios::sync_with_stdio(false);
Euler_Sieve(MAXN - 5);
cin >> T;
while(T--){
cin >> N >> M;
int l, r, top = min(N, M); LL ans = 0;
for(l = 1; l <= top; l = r + 1){
r = min(N / (N / l), M / (M / l));
ans += 1LL * (pre[r] - pre[l - 1]) * sum[N / l] * sum[M / l];
}
cout << ans << endl;
}
return 0;
}
void Euler_Sieve(int top){
int i, j;
mu[1] = 1;
for(i = 2; i <= top; i++){
if(!noprime[i]) prime[++cnt_p] = i, mu[i] = -1;
for(j = 1; j <= cnt_p && prime[j] * i <= top; j++){
noprime[prime[j] * i] = true;
if(i % prime[j] == 0) break;
mu[prime[j] * i] = -mu[i];
}
}
for(i = 1; i <= top; i++) pre[i] = pre[i - 1] + mu[i];
int l, r;
for(i = 1; i <= top; i++){
for(l = 1; l <= i; l = r + 1){
r = i / (i / l);
sum[i] += 1LL * (i / l) * (r - l + 1);
}
}
}