狄利克雷卷积

定义

数论函数

定义域为正整数的函数,称为数论函数。

常见数论函数:

函数符号名称定义
ε ( n ) \varepsilon(n) ε(n)单位函数 ε ( n ) = [ n = 1 ] \varepsilon(n)=[n=1] ε(n)=[n=1],即仅当 n = 1 n=1 n=1 时为 1 1 1,其余为 0 0 0
1 ( n ) \mathbf{1}(n) 1(n)常数函数 1 ( n ) = 1 \mathbf{1}(n)=1 1(n)=1,对任意正整数取值都为 1 1 1
i d ( n ) \mathrm{id}(n) id(n)恒等函数 i d ( n ) = n \mathrm{id}(n)=n id(n)=n
i d k ( n ) \mathrm{id}_k(n) idk(n)幂函数 i d k ( n ) = n k \mathrm{id}_k(n)=n^k idk(n)=nk
μ ( n ) \mu(n) μ(n)莫比乌斯函数按照因子个数取 ( − 1 ) k (-1)^k (1)k 0 0 0
φ ( n ) \varphi(n) φ(n)欧拉函数 1 ∼ n 1\sim n 1n 中与 n n n 互质的数的个数
d ( n ) d(n) d(n)约数个数函数 n n n 的正约数的个数
σ ( n ) \sigma(n) σ(n)约数和函数 n n n 的所有正约数的和

狄利克雷卷积

狄利克雷卷积就是在数论函数上的一种乘法运算,将复杂的交换求和过程转化成类似整式乘法的卷积运算,缩短公式的推导。

同时将欧拉函数,约数和函数通过简单的卷积运算得到。

狄利克雷卷积的定义公式

f , g f, g f,g 是两个数论函数,它们的狄利克雷卷积记作 f ∗ g f * g fg,结果仍是一个数论函数,其定义为:

( f ∗ g ) ( n ) = ∑ d ∣ n f ( d ) ⋅ g ( n d ) (f * g)(n) = \sum_{d \mid n} f(d) \cdot g\left(\frac{n}{d}\right) (fg)(n)=dnf(d)g(dn)

性质

交换律

f ∗ g = g ∗ f f*g=g*f fg=gf

结合律

( f ∗ g ) ∗ h = f ∗ ( g ∗ h ) (f * g) * h = f * (g * h) (fg)h=f(gh)

分配律

f ∗ ( g + h ) = f ∗ g + f ∗ h f * (g + h) = f * g + f * h f(g+h)=fg+fh

单位函数

单位函数 ε \varepsilon ε 是狄利克雷卷积的单位元,即对任意数论函数 f f f,有

f ∗ ε = f f * \varepsilon = f fε=f

卷积逆元

对于满足 f ( 1 ) ≠ 0 f(1) \neq 0 f(1)=0 的数论函数 f f f,存在唯一的函数 f − 1 f^{-1} f1,使得
f ∗ f − 1 = ε f * f^{-1} = \varepsilon ff1=ε
f − 1 f^{-1} f1 f f f 的狄利克雷逆元。

特殊等式

  1. 1 ∗ μ = ε \mathbf{1} * \mu = \varepsilon 1μ=ε
  2. 1 ∗ 1 = d \mathbf{1} * \mathbf{1} = d 11=d
  3. 1 ∗ i d = σ \mathbf{1} * id = \sigma 1id=σ
  4. 1 ∗ φ = i d \mathbf{1} * \varphi = id 1φ=id
  5. i d ∗ μ = φ id * \mu = \varphi idμ=φ

证明可以带入前面的狄利克雷卷积的定义式中。

所以前面的莫比乌斯反演的第一形式可以用这特殊等式轻松证明,证明如下:

定理:若 F = f ∗ 1 F = f * \mathbf{1} F=f1,即
F ( n ) = ∑ d ∣ n f ( d ) F(n) = \sum_{d \mid n} f(d) F(n)=dnf(d)
则有
f ( n ) = ∑ d ∣ n F ( d ) ⋅ μ ( n d ) f(n) = \sum_{d \mid n} F(d) \cdot \mu\left(\frac{n}{d}\right) f(n)=dnF(d)μ(dn)

已知 F = f ∗ 1 F = f * \mathbf{1} F=f1,两边同时右乘 μ \mu μ
F ∗ μ = ( f ∗ 1 ) ∗ μ F * \mu = (f * \mathbf{1}) * \mu Fμ=(f1)μ

由结合律:
F ∗ μ = f ∗ ( 1 ∗ μ ) F * \mu = f * (\mathbf{1} * \mu) Fμ=f(1μ)

代入 1 ∗ μ = ε \mathbf{1} * \mu = \varepsilon 1μ=ε
F ∗ μ = f ∗ ε = f F * \mu = f * \varepsilon = f Fμ=fε=f

证毕。

积性定理

f f f g g g 都是积性函数,则它们的狄利克雷卷积 f ∗ g f * g fg 也是积性函数。

证明:设 gcd ⁡ ( a , b ) = 1 \gcd(a, b) = 1 gcd(a,b)=1,需证
( f ∗ g ) ( a b ) = ( f ∗ g ) ( a ) ⋅ ( f ∗ g ) ( b ) (f * g)(ab) = (f * g)(a) \cdot (f * g)(b) (fg)(ab)=(fg)(a)(fg)(b)

展开左边
( f ∗ g ) ( a b ) = ∑ d ∣ a b f ( d ) g ( a b / d ) (f * g)(ab) = \sum_{d \mid ab} f(d)g(ab/d) (fg)(ab)=dabf(d)g(ab/d)

由于 a , b a, b a,b 互质, a b ab ab 的每个约数 d d d 都可以唯一拆分为 d = d 1 d 2 d = d_1d_2 d=d1d2,其中 d 1 ∣ a d_1 \mid a d1a d 2 ∣ b d_2 \mid b d2b,且 gcd ⁡ ( d 1 , d 2 ) = 1 \gcd(d_1, d_2) = 1 gcd(d1,d2)=1

代入得:
( f ∗ g ) ( a b ) = ∑ d 1 ∣ a ∑ d 2 ∣ b f ( d 1 d 2 ) g ( a d 1 ⋅ b d 2 ) (f * g)(ab) = \sum_{d_1 \mid a} \sum_{d_2 \mid b} f(d_1d_2)g\left(\frac{a}{d_1} \cdot \frac{b}{d_2}\right) (fg)(ab)=d1ad2bf(d1d2)g(d1ad2b)
= ∑ d 1 ∣ a ∑ d 2 ∣ b f ( d 1 ) f ( d 2 ) g ( a / d 1 ) g ( b / d 2 ) = \sum_{d_1 \mid a} \sum_{d_2 \mid b} f(d_1)f(d_2)g(a/d_1)g(b/d_2) =d1ad2bf(d1)f(d2)g(a/d1)g(b/d2)
= ( ∑ d 1 ∣ a f ( d 1 ) g ( a / d 1 ) ) ⋅ ( ∑ d 2 ∣ b f ( d 2 ) g ( b / d 2 ) ) = \left(\sum_{d_1 \mid a} f(d_1)g(a/d_1)\right) \cdot \left(\sum_{d_2 \mid b} f(d_2)g(b/d_2)\right) = d1af(d1)g(a/d1) d2bf(d2)g(b/d2)
= ( f ∗ g ) ( a ) ⋅ ( f ∗ g ) ( b ) = (f * g)(a) \cdot (f * g)(b) =(fg)(a)(fg)(b)

因为 1 \mathbf{1} 1 μ \mu μ i d \mathrm{id} id 都是积性函数,所以由它们卷积得到的 d ( n ) d(n) d(n) σ ( n ) \sigma(n) σ(n) φ ( n ) \varphi(n) φ(n) 也都是积性函数,所以也可以用线性筛处理。

例题

CF1900D Small GCD

传送门

我们发现我们可以先将原数组排序。

那么答案就为:

A n s = ∑ i = 1 n ∑ j = i + 1 n ( n − j ) g c d ( a i , a j ) Ans = \sum\limits_{i=1}^n \sum\limits_{j=i+1}^n (n - j) gcd(a_i,a_j) Ans=i=1nj=i+1n(nj)gcd(ai,aj)

利用欧拉反演公式替换 gcd ⁡ \gcd gcd

gcd ⁡ ( a i , a j ) = ∑ d ∣ gcd ⁡ ( a i , a j ) φ ( d ) = ∑ d ∣ a i , d ∣ a j φ ( d ) \gcd(a_i, a_j) = \sum_{d \mid \gcd(a_i, a_j)} \varphi(d) = \sum_{d \mid a_i , d \mid a_j} \varphi(d) gcd(ai,aj)=dgcd(ai,aj)φ(d)=dai,dajφ(d)

代入求和式,并交换求和顺序:

Ans = ∑ j = 2 n − 1 ( n − j ) ∑ d ∣ a j φ ( d ) ∑ i = 1 j − 1 [ d ∣ a i ] \text{Ans} = \sum_{j=2}^{n-1} (n-j) \sum_{d \mid a_j} \varphi(d) \sum_{i=1}^{j-1} [d \mid a_i] Ans=j=2n1(nj)dajφ(d)i=1j1[dai]

观察式子最后的 ∑ i = 1 j − 1 [ d ∣ a i ] \sum_{i=1}^{j-1} [d \mid a_i] i=1j1[dai],我们发现它的几何意义为在当前遍历到的 a j a_j aj 之前,有多少个数是 d d d 的倍数。

#include<bits/stdc++.h>
#define int long long

using namespace std;

const int MAXX = 1e5 + 5, INF = 1e5 + 2;

int n, a[MAXX], num[MAXX], prime[MAXX], cnt, phi[MAXX], vis[MAXX], sum[MAXX], ans, t;

void init() {
	num[0] = 1;
	for(int i = 1; i <= INF; i++) num[i] = num[i - 1] * i;
    phi[1] = 1;
    for(int i = 2; i <= INF; i++) {
        if(!vis[i]) {
            prime[++cnt] = i;
            phi[i] = i - 1;
        }
        for(int j = 1; j <= cnt && i * prime[j] <= INF; j++) {
            vis[i * prime[j]] = 1;
            if(i % prime[j] == 0) {
                phi[i * prime[j]] = phi[i] * prime[j];
                break;
            }
            else {
                phi[i * prime[j]] = phi[i] * phi[prime[j]];
            }
        }
    }
    for(int i = 1; i <= INF; i++) sum[i] = sum[i - 1] + phi[i];
}

void solve(){
    cin >> n; ans = 0;
    for(int i = 1; i <= n; i++) cin >> a[i];
    for(int i = 1; i <= INF; i++) sum[i] = 0;
    sort(a + 1, a + 1 + n);
    for(int j = 1; j <= n - 1; j++){
        int num = 0;
        for(int d = 1; d * d <= a[j]; d++){
            if(a[j] % d == 0){
                num += phi[d] * sum[d];
                if(d * d != a[j]) num += phi[a[j] / d] * sum[a[j] / d];
            }
        }
        ans = (ans + num * (n - j));
        for(int d = 1; d * d <= a[j]; d++){
            if(a[j] % d == 0){
                sum[d]++;
                if(d * d != a[j]) sum[a[j] / d]++;
            }
        }
    }
    cout << ans << '\n';
}

signed main(){
    init();
    cin >> t;
    while(t--) solve();
    return 0;
}

P1829 [集训队互测 2010] Crash的数字表格 / JZPTAB

传送门

由题得:
A n s = ∑ i = 1 n ∑ j = 1 m lcm ⁡ ( i , j ) Ans = \sum_{i=1}^{n}\sum_{j=1}^{m}\operatorname{lcm}(i,j) Ans=i=1nj=1mlcm(i,j)

lcm ⁡ ( i , j ) = i ⋅ j gcd ⁡ ( i , j ) \operatorname{lcm}(i,j)=\dfrac{i\cdot j}{\gcd(i,j)} lcm(i,j)=gcd(i,j)ij,交换枚举顺序:

A n s = ∑ d = 1 n ∑ i = 1 n ∑ j = 1 m [ gcd ⁡ ( i , j ) = d ] i ⋅ j d Ans=\sum_{d=1}^{n}\sum_{i=1}^{n}\sum_{j=1}^{m}[\gcd(i,j)=d]\frac{i\cdot j}{d} Ans=d=1ni=1nj=1m[gcd(i,j)=d]dij

i = x d ,   j = y d i=xd,\ j=yd i=xd, j=yd 代入原式:

A n s = ∑ d = 1 n ∑ x = 1 ⌊ n / d ⌋ ∑ y = 1 ⌊ m / d ⌋ [ gcd ⁡ ( x , y ) = 1 ] ⋅ x ⋅ y Ans=\sum_{d=1}^{n}\sum_{x=1}^{\lfloor n/d\rfloor}\sum_{y=1}^{\lfloor m/d\rfloor}[\gcd(x,y)=1]\cdot x\cdot y Ans=d=1nx=1n/dy=1m/d[gcd(x,y)=1]xy

所以设:

S ( N , M ) = ∑ x = 1 N ∑ y = 1 M [ gcd ⁡ ( x , y ) = 1 ] ⋅ x ⋅ y S(N,M)=\sum_{x=1}^{N}\sum_{y=1}^{M}[\gcd(x,y)=1]\cdot x\cdot y S(N,M)=x=1Ny=1M[gcd(x,y)=1]xy

代入 [ gcd ⁡ ( x , y ) = 1 ] = ∑ k ∣ x ,   k ∣ y μ ( k ) [\gcd(x,y)=1]=\sum_{k\mid x,\ k\mid y}\mu(k) [gcd(x,y)=1]=kx, kyμ(k),设 x = u k ,   y = v k x=uk,\ y=vk x=uk, y=vk

S ( N , M ) = ∑ x = 1 N ∑ y = 1 M x y ∑ k ∣ x ,   k ∣ y μ ( k ) S(N,M)=\sum_{x=1}^{N}\sum_{y=1}^{M}xy\sum_{k\mid x,\ k\mid y}\mu(k) S(N,M)=x=1Ny=1Mxykx, kyμ(k)

= ∑ k = 1 min ⁡ ( N , M ) μ ( k ) ∑ u = 1 ⌊ N / k ⌋ ∑ v = 1 ⌊ M / k ⌋ ( u k ) ⋅ ( v k ) =\sum_{k=1}^{\min(N,M)}\mu(k)\sum_{u=1}^{\lfloor N/k\rfloor}\sum_{v=1}^{\lfloor M/k\rfloor}(uk)\cdot(vk) =k=1min(N,M)μ(k)u=1N/kv=1M/k(uk)(vk)

= ∑ k = 1 min ⁡ ( N , M ) μ ( k ) ⋅ k 2 ( ∑ u = 1 ⌊ N / k ⌋ u ) ( ∑ v = 1 ⌊ M / k ⌋ v ) =\sum_{k=1}^{\min(N,M)}\mu(k)\cdot k^2\left(\sum_{u=1}^{\lfloor N/k\rfloor}u\right)\left(\sum_{v=1}^{\lfloor M/k\rfloor}v\right) =k=1min(N,M)μ(k)k2 u=1N/ku v=1M/kv

( ∑ u = 1 ⌊ N / k ⌋ u ) ( ∑ v = 1 ⌊ M / k ⌋ v ) \left(\sum_{u=1}^{\lfloor N/k\rfloor}u\right)\left(\sum_{v=1}^{\lfloor M/k\rfloor}v\right) u=1N/ku v=1M/kv 后面的这个可以用整除分块解决。

所以:

A n s = ∑ d = 1 min ⁡ ( n , m ) d ∑ k = 1 min ⁡ ( ⌊ n / d ⌋ , ⌊ m / d ⌋ ) μ ( k ) ⋅ k 2 ( ∑ u = 1 ⌊ N / k ⌋ u ) ( ∑ v = 1 ⌊ M / k ⌋ v ) Ans=\sum_{d=1}^{\min(n,m)}d\sum_{k=1}^{\min(\lfloor n/d\rfloor,\lfloor m/d\rfloor)}\mu(k)\cdot k^2\left(\sum_{u=1}^{\lfloor N/k\rfloor}u\right)\left(\sum_{v=1}^{\lfloor M/k\rfloor}v\right) Ans=d=1min(n,m)dk=1min(⌊n/d,m/d⌋)μ(k)k2 u=1N/ku v=1M/kv

T = d k T=dk T=dk 代入:

A n s = ∑ T = 1 min ⁡ ( n , m ) ( ∑ u = 1 ⌊ N / k ⌋ u ) ( ∑ v = 1 ⌊ M / k ⌋ v ) ∑ k ∣ T T k ⋅ μ ( k ) ⋅ k 2 Ans=\sum_{T=1}^{\min(n,m)}\left(\sum_{u=1}^{\lfloor N/k\rfloor}u\right)\left(\sum_{v=1}^{\lfloor M/k\rfloor}v\right)\sum_{k\mid T}\frac{T}{k}\cdot\mu(k)\cdot k^2 Ans=T=1min(n,m) u=1N/ku v=1M/kv kTkTμ(k)k2

虽然现在这个可以直接做了,但是我们考虑继续优化,我们观察后面的部分。

∑ k ∣ T T k ⋅ μ ( k ) ⋅ k 2 = T ∑ k ∣ T k ⋅ μ ( k ) \sum_{k\mid T}\frac{T}{k}\cdot\mu(k)\cdot k^2 = T\sum_{k\mid T}k\cdot\mu(k) kTkTμ(k)k2=TkTkμ(k)

又因为 ∑ k ∣ T k μ ( k ) \sum\limits_{k\mid T}k\mu(k) kTkμ(k) 是积性函数 ( id ⁡ ⋅ μ ) (\operatorname{id}\cdot\mu) (idμ) 1 \mathbf{1} 1 的卷积,因此 T ∑ k ∣ T k ⋅ μ ( k ) T\sum_{k\mid T}k\cdot\mu(k) TkTkμ(k) 依然是积性函数,用线性筛处理即可。

#include<bits/stdc++.h>
#define int long long

using namespace std;

const int MAXX = 1e7 + 5, M = 20101009, INF = 1e7 + 2;

int n, m, p[MAXX], prime[MAXX], cnt, sum[MAXX], ans, vis[MAXX];

void init(){
    p[1] = 1;
    for(int i = 2; i <= INF; i++) {
        if(!vis[i]) {
            prime[++cnt] = i;
            p[i] = ((1 - i) * i % M + M) % M;
        }
        for(int j = 1; j <= cnt && i * prime[j] <= INF; j++) {
            vis[i * prime[j]] = 1;
            if(i % prime[j] == 0) {
                p[i * prime[j]] = p[i] * prime[j] % M;
                break;
            }else p[i * prime[j]] = p[i] * p[prime[j]] % M;
        }
    }
    for(int i = 1; i <= INF; i++) sum[i] = (sum[i - 1] + p[i]) % M;
}

signed main(){
    init();
    cin >> n >> m;
    for(int l = 1, r; l <= min(n, m); l = r + 1){
        r = min(n / (n / l), m / (m / l));
        ans = (ans + ((n / l) * (n / l + 1) / 2) % M * ((m / l) * (m / l + 1) / 2 % M) % M * ((sum[r] - sum[l - 1] + M) % M) % M) % M;
    }
    cout << ans << '\n';
    return 0;
}

综合题目练习

abc020D

这道题是一个典型的套路题。

我们先将 l c m lcm lcm 转换:

A n s = ∑ i = 1 n i k g c d ( i , k ) Ans = \sum_{i=1}^n \frac{ik}{gcd(i,k)} Ans=i=1ngcd(i,k)ik

= ∑ i = 1 n ∑ d = 1 i i k d [ g c d ( i , k / d ) = 1 ] = \sum_{i=1}^n \sum_{d=1}^i \frac{ik}{d}[gcd(i,k/d) = 1] =i=1nd=1idik[gcd(i,k/d)=1]

= ∑ i = 1 n ∑ d = 1 i i k d ∑ g ∣ g c d ( i , k / d ) μ ( g ) =\sum_{i=1}^n \sum_{d=1}^i \frac{ik}{d} \sum_{g| gcd(i,k/d)} \mu(g) =i=1nd=1idikggcd(i,k/d)μ(g)

= k ∑ d ∣ k ∑ i = 1 ⌊ n / d ⌋ i ∑ g ∣ g c d ( i , k / d ) μ ( g ) =k\sum_{d|k} \sum_{i=1}^{\lfloor n/d \rfloor} i \sum_{g| gcd(i,k/d)} \mu(g) =kdki=1n/diggcd(i,k/d)μ(g)

= k ∑ d ∣ k ∑ g ∣ k / d μ ( g ) ∑ i = 1 ⌊ n / d g ⌋ i g =k\sum_{d|k}\sum_{g| k/d} \mu(g) \sum_{i=1}^{\lfloor n/dg \rfloor} ig =kdkgk/dμ(g)i=1n/dgig

然后预处理 k k k 的因数即可AC此题

#include<bits/stdc++.h>
#define int long long

using namespace std;

const int MAXX = 1e5 + 5, M = 1e9 + 7;

int n, k, num[MAXX], cnt, ans, sum[MAXX];

int mu(int n){
	int res = 1;
	for(int i = 2; i * i <= n; i++){
		if(n % i == 0){
			int zrr = 0;
			while(n % i == 0) n /= i, zrr++;
			if(zrr >= 2) return 0;
			res = -res;
		}
	}
	if(n != 1) res = -res;
	return res;
}

__int128_t SUM(__int128_t x){
	return (1 + x) * x / 2 % M;
}

signed main(){
	cin >> n >> k;
	for(int i = 1; i * i <= k; i++){
		if(k % i == 0){
			num[++cnt] = i;
			if(i * i != k) num[++cnt] = (k / i);
		}
	}
	sort(num + 1, num + 1 + cnt);
	for(int i = 1; i <= cnt; i++) sum[i] = mu(num[i]);
	for(int d = 1; d <= cnt; d++){
		int res = 0;
		for(int g = 1; g <= cnt; g++){
			if((k / num[d]) % num[g] != 0) continue;
			res = (res + sum[g] * num[g] % M * SUM(n / num[d] / num[g]) % M + M) % M;
		}
		ans = (ans + res) % M;
	}
	cout << ans * k % M;
	return 0;
}

P2231

由于裴蜀定理可以知道当为合法情况的时候仅当 g c d { a 1 , a 2 , a 3 … a n } = 1 gcd\{a_1,a_2,a_3 \dots a_n\} = 1 gcd{a1,a2,a3an}=1

然后我们直接大力莫反:

Ans = ∑ 1 ≤ a 1 ≤ M ⋯ ∑ 1 ≤ a N ≤ M [ gcd ⁡ ( a 1 , … , a N , M ) = 1 ] \text{Ans} = \sum_{1 \le a_1 \le M} \cdots \sum_{1 \le a_N \le M} [\gcd(a_1, \ldots, a_N, M) = 1] Ans=1a1M1aNM[gcd(a1,,aN,M)=1]

= ∑ d ∣ M μ ( d ) ( ∑ 1 ≤ a 1 ≤ M ,   d ∣ a 1 1 ) ⋯ ( ∑ 1 ≤ a N ≤ M ,   d ∣ a N 1 ) = \sum_{d \mid M} \mu(d) \left( \sum_{1 \le a_1 \le M,\, d \mid a_1} 1 \right) \cdots \left( \sum_{1 \le a_N \le M,\, d \mid a_N} 1 \right) =dMμ(d) 1a1M,da11 1aNM,daN1

= ∑ d ∣ M μ ( d ) ( M d ) N = \sum_{d \mid M} \mu(d) \left( \frac{M}{d} \right)^N =dMμ(d)(dM)N

#include<bits/stdc++.h>
#define int long long

using namespace std;

int n, m, cnt, ans;

int qpow(int a, int b){
	int res = 1;
	while(b){
		if(b & 1) res = res * a;
		a = a * a, b /= 2;
	}
	return res;
}

int mu(int n){
	int res = 1;
	for(int i = 2; i * i <= n; i++){
		if(n % i == 0){
			int zrr = 0;
			while(n % i == 0) n /= i, zrr++;
			if(zrr >= 2) return 0;
			res = -res;
		}
	}
	if(n != 1) res = -res;
	return res;
}

signed main(){
	cin >> n >> m;
	for(int i = 1; i * i <= m; i++){
		if(m % i == 0){
			ans += mu(i) * qpow(m / i, n);
			if(i * i != m) ans += mu(m / i) * qpow(i, n);
		} 
	}
	cout << ans << '\n';
	return 0;
}

CF235E

前置知识

d ( i j ) = ∑ x ∣ i ∑ y ∣ j [ g c d ( x , y ) = 1 ] d(ij)=\sum\limits_{x|i} \sum\limits_{y|j}[gcd(x,y)=1] d(ij)=xiyj[gcd(x,y)=1]

有公式可转换:

d ( i ⋅ j ⋅ k ) = ∑ u ∣ i ∑ v ∣ j ∑ w ∣ k [ gcd ⁡ ( u , v ) = 1 ] [ gcd ⁡ ( v , w ) = 1 ] [ gcd ⁡ ( w , u ) = 1 ] d(i \cdot j \cdot k) = \sum_{u|i} \sum_{v|j} \sum_{w|k} [\gcd(u, v) = 1][\gcd(v, w) = 1][\gcd(w, u) = 1] d(ijk)=uivjwk[gcd(u,v)=1][gcd(v,w)=1][gcd(w,u)=1]

然后我们暴力莫反:

[ gcd ⁡ ( u , v ) = 1 ] = ∑ x ∣ u , x ∣ v μ ( x ) [\gcd(u, v) = 1] = \sum_{x|u, x|v} \mu(x) [gcd(u,v)=1]=xu,xvμ(x)

[ gcd ⁡ ( v , w ) = 1 ] = ∑ y ∣ v , y ∣ w μ ( y ) [\gcd(v, w) = 1] = \sum_{y|v, y|w} \mu(y) [gcd(v,w)=1]=yv,ywμ(y)

[ gcd ⁡ ( w , u ) = 1 ] = ∑ z ∣ w , z ∣ u μ ( z ) [\gcd(w, u) = 1] = \sum_{z|w, z|u} \mu(z) [gcd(w,u)=1]=zw,zuμ(z)

将其带入,交换求和顺序:

Ans = ∑ x = 1 a μ ( x ) ∑ y = 1 b μ ( y ) ∑ z = 1 c μ ( z ) ( ∑ x ∣ u , z ∣ u ⌊ a u ⌋ ) ( ∑ x ∣ v , y ∣ v ⌊ b v ⌋ ) ( ∑ y ∣ w , z ∣ w ⌊ c w ⌋ ) \text{Ans} = \sum_{x=1}^{a} \mu(x) \sum_{y=1}^{b} \mu(y) \sum_{z=1}^{c} \mu(z) \left( \sum_{x|u, z|u} \left\lfloor \frac{a}{u} \right\rfloor \right) \left( \sum_{x|v, y|v} \left\lfloor \frac{b}{v} \right\rfloor \right) \left( \sum_{y|w, z|w} \left\lfloor \frac{c}{w} \right\rfloor \right) Ans=x=1aμ(x)y=1bμ(y)z=1cμ(z) xu,zuua xv,yvvb yw,zwwc

我们设:

S ( N , M ) = ∑ M ∣ k ⌊ N k ⌋ = ∑ t = 1 ⌊ N / M ⌋ ⌊ N M ⋅ t ⌋ S(N, M) = \sum_{M|k} \left\lfloor \frac{N}{k} \right\rfloor = \sum_{t=1}^{\lfloor N/M \rfloor} \left\lfloor \frac{N}{M \cdot t} \right\rfloor S(N,M)=MkkN=t=1N/MMtN

又:

∑ lcm ( x , z ) ∣ u ⌊ a u ⌋ = S ( a , lcm ( x , z ) ) \sum_{\text{lcm}(x,z) \mid u} \left\lfloor \frac{a}{u} \right\rfloor = S(a, \text{lcm}(x, z)) lcm(x,z)uua=S(a,lcm(x,z))

∑ lcm ( x , y ) ∣ v ⌊ b v ⌋ = S ( b , lcm ( x , y ) ) \sum_{\text{lcm}(x,y) \mid v} \left\lfloor \frac{b}{v} \right\rfloor = S(b, \text{lcm}(x, y)) lcm(x,y)vvb=S(b,lcm(x,y))

∑ lcm ( y , z ) ∣ w ⌊ c w ⌋ = S ( c , lcm ( y , z ) ) \sum_{\text{lcm}(y,z) \mid w} \left\lfloor \frac{c}{w} \right\rfloor = S(c, \text{lcm}(y, z)) lcm(y,z)wwc=S(c,lcm(y,z))

然后我们暴力处理,对于 μ = 0 \mu = 0 μ=0
的时候直接结束循环,并且与处理 S S S l c m lcm lcm 即可AC此题。

将其整理:

Ans = ∑ x = 1 a μ ( x ) ∑ y = 1 b μ ( y ) ∑ z = 1 c μ ( z ) ⋅ S ( a , lcm ( x , z ) ) ⋅ S ( b , lcm ( x , y ) ) ⋅ S ( c , lcm ( y , z ) ) \text{Ans} = \sum_{x=1}^{a} \mu(x) \sum_{y=1}^{b} \mu(y) \sum_{z=1}^{c} \mu(z) \cdot S(a, \text{lcm}(x, z)) \cdot S(b, \text{lcm}(x, y)) \cdot S(c, \text{lcm}(y, z)) Ans=x=1aμ(x)y=1bμ(y)z=1cμ(z)S(a,lcm(x,z))S(b,lcm(x,y))S(c,lcm(y,z))

#include<bits/stdc++.h>
#define int long long

using namespace std;

const int MAXX = 2e3 + 5, INF = 2e3 + 2, M = 1073741824;

int a, b, c, mu[MAXX], vis[MAXX], s[MAXX][MAXX], LCM[MAXX][MAXX], ans;
vector<int> p;

void init(){
	for(int n = 1; n <= INF; n++){
		for(int m = 1; m <= n; m++){
			for(int k = 1; k <= n / m; k++) s[n][m] = (s[n][m] + n / (m * k)) % M;
		}
	}
	for(int i = 1; i <= INF; i++){
		for(int j = 1; j <= INF; j++) LCM[i][j] = i * j / __gcd(i, j);
	}
	mu[1] = 1;
    for(int i = 2; i <= INF; i++){
        if(!vis[i]) p.push_back(i), mu[i] = -1;
    	for(int j : p){
      	  if(i * j > INF) break;
      	  vis[i * j] = 1, mu[i * j] = -mu[i];
      	  if(i % j == 0){ mu[i * j] = 0; break; }
    	}
    }
}


signed main(){
	init();
	cin >> a >> b >> c;
    for(int x = 1; x <= a; x++){
        if(mu[x] == 0) continue;
        for(int y = 1; y <= b; y++){
            if(mu[y] == 0) continue;
            if(LCM[x][y] > a) continue;
            for(int z = 1; z <= c; z++){
                if(mu[z] == 0) continue;
                if(LCM[y][z] > b) continue;
                if(LCM[x][z] > c) continue;
                if(mu[x] * mu[y] * mu[z] == 1) ans = (ans + s[a][LCM[x][y]] * s[b][LCM[z][y]] % M * s[c][LCM[x][z]] % M) % M;
                else ans = (ans - s[a][LCM[x][y]] * s[b][LCM[z][y]] % M * s[c][LCM[x][z]] % M + M) % M;
            }
        }
    }
    cout << ans << "\n";
	return 0;
}

P10584

前置知识,重要恒等式

μ 2 ( d ) = ∑ k 2 ∣ d μ ( k ) \mu^2(d) = \sum_{k^2 \mid d} \mu(k) μ2(d)=k2dμ(k)

任意正整数 x x x 表示为 x = d ⋅ y 2 x = d \cdot y^2 x=dy2,我们称 (d) 为“平方因子自由数”。

i ⋅ j = ( d 1 x 2 ) ⋅ ( d 2 y 2 ) = d 1 d 2 ( x y ) 2 i \cdot j = (d_1 x^2) \cdot (d_2 y^2) = d_1 d_2 (xy)^2 ij=(d1x2)(d2y2)=d1d2(xy)2 是完全平方数,当且仅当 d 1 = d 2 d_1 = d_2 d1=d2

所以设 i = d ⋅ x 2 i = d \cdot x^2 i=dx2 j = d ⋅ y 2 j = d \cdot y^2 j=dy2(其中 μ 2 ( d ) = 1 \mu^2(d) = 1 μ2(d)=1):

  • 1 ≤ d ⋅ x 2 ≤ n    ⟹    1 ≤ x ≤ ⌊ n d ⌋ 1 \leq d \cdot x^2 \leq n \implies 1 \leq x \leq \left\lfloor \sqrt{\frac{n}{d}} \right\rfloor 1dx2n1xdn
  • 1 ≤ d ⋅ y 2 ≤ m    ⟹    1 ≤ y ≤ ⌊ m d ⌋ 1 \leq d \cdot y^2 \leq m \implies 1 \leq y \leq \left\lfloor \sqrt{\frac{m}{d}} \right\rfloor 1dy2m1ydm

原式可转化为对 d d d 的求和:

Ans = ∑ d = 1 min ⁡ ( n , m ) μ 2 ( d ) ⌊ n d ⌋ ⌊ m d ⌋ \text{Ans} = \sum_{d=1}^{\min(n,m)} \mu^2(d) \left\lfloor \sqrt{\frac{n}{d}} \right\rfloor \left\lfloor \sqrt{\frac{m}{d}} \right\rfloor Ans=d=1min(n,m)μ2(d)dn dm

我们直接将公式代入:
Ans = ∑ d = 1 min ⁡ ( n , m ) ( ∑ k 2 ∣ d μ ( k ) ) ⌊ n d ⌋ ⌊ m d ⌋ \text{Ans} = \sum_{d=1}^{\min(n,m)} \left( \sum_{k^2|d} \mu(k) \right) \left\lfloor \sqrt{\frac{n}{d}} \right\rfloor \left\lfloor \sqrt{\frac{m}{d}} \right\rfloor Ans=d=1min(n,m) k2dμ(k) dn dm

= ∑ k = 1 ⌊ min ⁡ ( n , m ) ⌋ μ ( k ) ∑ t = 1 ⌊ min ⁡ ( n , m ) / k 2 ⌋ ⌊ n k 2 t ⌋ ⌊ m k 2 t ⌋ = \sum_{k=1}^{\lfloor \sqrt{\min(n,m)} \rfloor} \mu(k) \sum_{t=1}^{\left\lfloor \min(n,m)/k^2 \right\rfloor} \left\lfloor \sqrt{\frac{n}{k^2 t}} \right\rfloor \left\lfloor \sqrt{\frac{m}{k^2 t}} \right\rfloor =k=1min(n,m) μ(k)t=1min(n,m)/k2k2tn k2tm

我们设:

h ( A , B ) = ∑ t = 1 min ⁡ ( A , B ) ⌊ A t ⌋ ⌊ B t ⌋ h(A, B) = \sum_{t=1}^{\min(A, B)} \left\lfloor \sqrt{\frac{A}{t}} \right\rfloor \left\lfloor \sqrt{\frac{B}{t}} \right\rfloor h(A,B)=t=1min(A,B)tA tB

所以最终结果就为:

Ans = ∑ k = 1 ⌊ min ⁡ ( n , m ) ⌋ μ ( k ) ⋅ h ( ⌊ n k 2 ⌋ , ⌊ m k 2 ⌋ ) \text{Ans} = \sum_{k=1}^{\lfloor \sqrt{\min(n,m)} \rfloor} \mu(k) \cdot h\left(\left\lfloor \frac{n}{k^2} \right\rfloor, \left\lfloor \frac{m}{k^2} \right\rfloor\right) Ans=k=1min(n,m) μ(k)h(k2n,k2m)

然后我们直接用二次分块加上线性筛预处理即可。

代码读者自写不难。

做题技巧

对于 g c d ( i , j ) = 1 gcd(i,j)=1 gcd(i,j)=1 或者 g c d ( i , j ) gcd(i,j) gcd(i,j) 在分母的情况我们要有先用莫比乌斯反演。

对于 g c d ( i , j ) gcd(i,j) gcd(i,j) 的普通情况我们先考虑欧拉反演公式。

Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐