[SDOI2015] 约数个数和 (莫比乌斯反演)

题意:

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=1Nj=1Md(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α1pkαk,j=p1β1pkβk,i×j=p1α1+β1pkα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)=xiyj[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=1Nj=1Mxiyj[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=1Nj=1Mxiyj[ngcd(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=1Nj=1Mxiyj[gcd(x,y)=n]

则有

g ( n ) = ∑ n ∣ d f ( d ) g(n)=\sum_{n\mid d} f(d) g(n)=ndf(d)

那么就可以莫比乌斯反演了

f ( n ) = ∑ n ∣ d μ ( d n ) g ( d ) f(n)=\sum_{n\mid d}\mu(\frac{d}{n})g(d) f(n)=ndμ(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)] [ngcd(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 xNyM

所以式子就变为了

∑ 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=1Ny=1MxNyM[ngcd(x,y)]

[ n ∣ gcd ⁡ ( x , y ) ] [n \mid \gcd(x,y)] [ngcd(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=1nNy=1nMnxNnyM

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=1Ny=1MxNyM

假设有二重积分

∬ 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)dxD2f(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=1NxNy=1MyM

h ( x ) = ∑ i = 1 x ⌊ x i ⌋ h(x)=\sum_{i=1}^{x}\lfloor\frac{x}{i} \rfloor h(x)=i=1xix

那么

f ( n ) = ∑ n ∣ d μ ( d n ) g ( d ) f(n)=\sum_{n\mid d}\mu(\frac{d}{n})g(d) f(n)=ndμ(nd)g(d)

答案为

f ( 1 ) = ∑ d = 1 N μ ( d ) g ( d ) f(1)=\sum_{d=1}^{N}\mu(d)g(d) f(1)=d=1Nμ(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=1min(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);
    }
}
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值