题意:
设 d ( x ) d(x) d(x) 为 x x x 的约数个数,求
∑ i = 1 N ∑ j = 1 M d ( i j ) \sum_{i=1}^{N}\sum_{j=1}^{M} d(ij) i=1∑Nj=1∑Md(ij)
分析:
首先 i = p 1 α 1 ⋯ p k α k , j = p 1 β 1 ⋯ p k β k , i × j = p 1 α 1 + β 1 ⋯ p k α k + β k i=p_1 ^{\alpha_1}\cdots p_k^{\alpha_k},j=p_1 ^{\beta_1}\cdots p_k^{\beta_k},i×j=p_1 ^{\alpha_1+\beta_1}\cdots p_k^{\alpha_k+\beta_k} i=p1α1⋯pkαk,j=p1β1⋯pkβk,i×j=p1α1+β1⋯pkαk+βk
约数个数和为
d ( i j ) = ( α 1 + β 1 + 1 ) ⋯ ( α k + β k + 1 ) = α 1 β 1 + α 1 β 2 + ⋯ + 1 d(ij)=(\alpha_1+\beta_1+1)\cdots(\alpha_k+\beta_k+1)=\alpha_1\beta_1+\alpha_1\beta_2+\cdots + 1 d(ij)=(α1+β1+1)⋯(αk+βk+1)=α1β1+α1β2+⋯+1
所以 d ( i j ) = ∑ x ∣ i ∑ y ∣ j [ gcd ( x , y ) = 1 ] d(ij)=\sum_{x|i}\sum_{y|j}[\gcd(x,y)=1] d(ij)=x∣i∑y∣j∑[gcd(x,y)=1]
所以原式为
∑ i = 1 N ∑ j = 1 M ∑ x ∣ i ∑ y ∣ j [ gcd ( x , y ) = 1 ] \sum_{i=1}^{N}\sum_{j=1}^{M}\sum_{x|i}\sum_{y|j}[\gcd(x,y)=1] i=1∑Nj=1∑Mx∣i∑y∣j∑[gcd(x,y)=1]
设 g ( n ) g(n) g(n) 为:
g ( n ) = ∑ i = 1 N ∑ j = 1 M ∑ x ∣ i ∑ y ∣ j [ n ∣ gcd ( x , y ) ] g(n)=\sum_{i=1}^{N}\sum_{j=1}^{M}\sum_{x|i}\sum_{y|j}[n\mid\gcd(x,y)] g(n)=i=1∑Nj=1∑Mx∣i∑y∣j∑[n∣gcd(x,y)]
设 f ( n ) f(n) f(n) 为:
∑ i = 1 N ∑ j = 1 M ∑ x ∣ i ∑ y ∣ j [ gcd ( x , y ) = n ] \sum_{i=1}^{N}\sum_{j=1}^{M}\sum_{x|i}\sum_{y|j}[\gcd(x,y)=n] i=1∑Nj=1∑Mx∣i∑y∣j∑[gcd(x,y)=n]
则有
g ( n ) = ∑ n ∣ d f ( d ) g(n)=\sum_{n\mid d} f(d) g(n)=n∣d∑f(d)
那么就可以莫比乌斯反演了
f ( n ) = ∑ n ∣ d μ ( d n ) g ( d ) f(n)=\sum_{n\mid d}\mu(\frac{d}{n})g(d) f(n)=n∣d∑μ(nd)g(d)
交换 g ( n ) g(n) g(n) 的求和次序
由于 x , y x,y x,y 分别是 i , j i,j i,j 的约数,所以可以先枚举 x , y x,y x,y
那么后面的 [ n ∣ gcd ( x , y ) ] [n \mid \gcd(x,y)] [n∣gcd(x,y)] 与 i , j i,j i,j 无关不需要考虑,所以只需要计算 i i i 中有多少 x x x 的倍数, j j j 中有多少 y y y 的倍数,所以是 ⌊ N x ⌋ ⌊ M y ⌋ \lfloor \frac{N}{x} \rfloor \lfloor \frac{M}{y} \rfloor ⌊xN⌋⌊yM⌋
所以式子就变为了
∑ x = 1 N ∑ y = 1 M ⌊ N x ⌋ ⌊ M y ⌋ [ n ∣ gcd ( x , y ) ] \sum_{x=1}^{N}\sum_{y=1}^{M}\lfloor \frac{N}{x} \rfloor \lfloor \frac{M}{y} \rfloor[n \mid \gcd(x,y)] x=1∑Ny=1∑M⌊xN⌋⌊yM⌋[n∣gcd(x,y)]
[ n ∣ gcd ( x , y ) ] [n \mid \gcd(x,y)] [n∣gcd(x,y)] 只需要关心 n n n 的倍数即可,那么就是
x ′ = x n , y ′ = y n x'=\frac{x}{n},y'=\frac{y}{n} x′=nx,y′=ny
替换得
∑ x ′ = 1 N n ∑ y ′ = 1 M n ⌊ N n x ′ ⌋ ⌊ M n y ′ ⌋ \sum_{x'=1}^{\frac{N}{n}}\sum_{y'=1}^{\frac{M}{n}} \lfloor\frac{N}{nx'} \rfloor \lfloor\frac{M}{ny'} \rfloor x′=1∑nNy′=1∑nM⌊nx′N⌋⌊ny′M⌋
设
N ′ = N n , M ′ = M n N'=\frac{N}{n},M'=\frac{M}{n} N′=nN,M′=nM
则
∑ x ′ = 1 N ′ ∑ y ′ = 1 M ′ ⌊ N ′ x ′ ⌋ ⌊ M ′ y ′ ⌋ \sum_{x'=1}^{N'}\sum_{y'=1}^{M'} \lfloor\frac{N'}{x'} \rfloor \lfloor\frac{M'}{y'} \rfloor x′=1∑N′y′=1∑M′⌊x′N′⌋⌊y′M′⌋
假设有二重积分
∬ D f ( x , y ) d x d y \iint_{D}f(x,y)\text{d}x\text{d}y ∬Df(x,y)dxdy
当区域 D D D 为矩形区域时,可以转为二次积分
∫ D 1 f ( x , y ) d x ∫ D 2 f ( x , y ) d y \int_{D_1}f(x,y)\text{d}x\int_{D_2}f(x,y)\text{d}y ∫D1f(x,y)dx∫D2f(x,y)dy
那么原式可以变为
∑ x ′ = 1 N ′ ⌊ N ′ x ′ ⌋ ∑ y ′ = 1 M ′ ⌊ M ′ y ′ ⌋ \sum_{x'=1}^{N'}\lfloor\frac{N'}{x'} \rfloor \sum_{y'=1}^{M'}\lfloor\frac{M'}{y'} \rfloor x′=1∑N′⌊x′N′⌋y′=1∑M′⌊y′M′⌋
设
h ( x ) = ∑ i = 1 x ⌊ x i ⌋ h(x)=\sum_{i=1}^{x}\lfloor\frac{x}{i} \rfloor h(x)=i=1∑x⌊ix⌋
那么
f ( n ) = ∑ n ∣ d μ ( d n ) g ( d ) f(n)=\sum_{n\mid d}\mu(\frac{d}{n})g(d) f(n)=n∣d∑μ(nd)g(d)
答案为
f ( 1 ) = ∑ d = 1 N μ ( d ) g ( d ) f(1)=\sum_{d=1}^{N}\mu(d)g(d) f(1)=d=1∑Nμ(d)g(d)
带入 g ( d ) g(d) g(d)
∑ i = 1 min ( N , M ) μ ( i ) h ( ⌊ N i ⌋ ) h ( ⌊ M i ⌋ ) \sum_{i=1}^{\min(N,M)}\mu(i)h(\lfloor \frac{N}{i} \rfloor)h(\lfloor \frac{M}{i} \rfloor) i=1∑min(N,M)μ(i)h(⌊iN⌋)h(⌊iM⌋)
可以用整除分块计算, h ( x ) h(x) h(x) 也同样可以用整除分块预处理。
代码:
#include <stdio.h>
#include <algorithm>
#define int long long
using namespace std;
const int N = 5e4 + 5;
int T, n, m, primes[N], mobius[N], cnt, sum[N], h[N];
bool st[N];
void get_mobius(int n) {
mobius[1] = 1;
for (int i = 2; i <= n; i ++) {
if (!st[i]) {
primes[cnt ++] = i;
mobius[i] = -1;
}
for (int j = 0; primes[j] * i <= n; j ++) {
int t = primes[j] * i;
st[t] = 1;
if (i % primes[j] == 0) {
mobius[t] = 0;
break;
}
mobius[t] = -mobius[i];
}
}
for (int i = 1; i <= n; i ++) sum[i] = sum[i - 1] + mobius[i];
}
void get_h(int n) {
for (int i = 1; i <= n; i ++) {
for (int l = 1, r; l <= i; l = r + 1) {
r = min(i, i / (i / l));
h[i] += (r - l + 1) * (i / l);
}
}
}
signed main() {
get_mobius(N - 1), get_h(N - 1);
scanf("%lld", &T);
while (T --) {
scanf("%lld%lld", &n, &m);
int res = 0, k = min(n, m);
for (int l = 1, r; l <= k; l = r + 1) {
r = min(k, min(n / (n / l), m / (m / l)));
res += (sum[r] - sum[l - 1]) * h[n / l] * h[m / l];
}
printf("%lld\n", res);
}
}