[筆記]莫比烏斯反演亂記

寫在前面

本文章已同步發佈在博主的博客園,也可以去那裏看

這是蒟蒻第一次寫這麼長的博文

如果覺得寫得湊合就點個支持吧qwqqwq

前置知識

積性函數狄利克雷卷積數論分塊(這一篇去找gyh吧我講也講不好)(有空慢慢補)

Mobius函數

定義

莫比烏斯函數μ(n)\mu(n)定義爲:

μ(n)={1,n=1(1)s,n=p1p2pssn0,n\mu(n)=\left\{ \begin{aligned} 1, & n=1 \\ (-1)^{s}, & n=p_1p_2…p_s(s爲n的本質不同的質因子個數)\\0,&n有平方因子\end{aligned} \right.

其中p1p2psp_1p_2…,p_s是不同素數。

可以看出,當nn沒有平方因子時,μ(n)\mu(n)非零。

μ\mu也是積性函數。

性質

莫比烏斯函數具有如下的性質:

dnμ(d)=ϵ(n)=[n=1]\sum_{d|n}\mu(d)=\epsilon(n)=[n=1]

使用狄利克雷卷積來表示,即

μ1=ϵ\mu*1=\epsilon

證明:

n=1n=1時顯然成立。

n>1n>1,設nnss個不同的素因子,由於μ(d)0\mu(d)\neq0當且僅當dd無平方因子,故dd中每個素因子的指數只能爲0011

nn的某個因子dd,有μ(d)=(1)i\mu(d)=(-1)^i,則它由ii個本質不同的質因子構成。因爲質因子的總數爲ss,所以滿足上式的因子數有CsiC_s^i個。

所以我們就可以對於原式,轉化爲枚舉μ(d)\mu(d)的值,同時運用二項式定理,故有

dnμ(d)=i=0sCsi×(1)i=i=0sCsi×(1)i×1si=(1+(1))s\sum_{d|n}\mu(d)=\sum_{i=0}^{s}C_s^i\times(-1)^i=\sum_{i=0}^{s}C_s^i\times(-1)^i\times 1^{s-i}=(1+(-1))^s

該式在s=0s=0n=1n=1時爲1,否則爲00

求莫比烏斯函數

因爲莫比烏斯函數是積性函數,所以可以用線性篩

int n, cnt, p[A], mu[A];
bool vis[A];

void getmu() {
    mu[1] = 1;
    for (int i = 2; i <= n; i++) {
	if (!vis[i]) mu[i] = -1, p[++cnt] = i;
	for (int j = 1; j <= cnt && i * p[j] <= n; j++) {
	    vis[i * p[j]] = 1;
	    if (i % p[j] == 0) { mu[i * p[j]] = 0; break; }
	    mu[i * p[j]] -= mu[i];
	}
    }
}

莫比烏斯反演公式

f(n)f(n)g(n)g(n)爲兩個數論函數。

如果有

f(n)=dng(d)f(n)=\sum\limits_{d|n}g(d)

則有

g(n)=dnμ(d)f(nd)g(n)=\sum\limits_{d|n}\mu(d)f(\frac{n}{d})

證明

  • 法一:對原式做數論變換

    1. dng(d)\sum\limits_{d|n}g(d)替換f(n)f(n),即

      dnμ(d)f(nd)=dnμ(d)kndg(k)\sum\limits_{d|n}\mu(d)f(\frac{n}{d})=\sum\limits_{d|n}\mu(d)\sum\limits_{k|\frac nd}g(k)

    2. 變換求和順序得

      kng(k)dnkμ(nk)\sum\limits_{k|n}g(k)\sum\limits_{d|\frac n k}\mu(\frac nk)

    3. 因爲dnμ(d)=[n=1]\sum\limits_{d|n}\mu(d)=[n=1],所以只有在nk=1\frac{n}{k}=1n=kn=k時纔會成立,所以上式等價於

      dn[n=k]g(k)=g(n)\sum\limits_{d|n}[n=k]g(k)=g(n)

    得證

  • 法二:利用卷積

    原問題爲:已知f=g1f=g*1,證明g=fμg=f*\mu

    轉化:fμ=g1μ=gε=gf*\mu=g*1*\mu=g*\varepsilon=g1μ=ε1*\mu=\varepsilon

    再次得證= =

小性質

[gcd(i,j)=1]dgcd(i,j)μ(d)[\gcd(i,j)=1]\Leftrightarrow\sum\limits_{d|\gcd(i,j)}\mu(d)

證明

  • 法一:

    n=gcd(i,j)n=\gcd(i,j),那麼等式右邊=dnμ(d)=[n=1]=[gcd(i,j)=1]==\sum\limits_{d|n}\mu(d)=[n=1]=[\gcd(i,j)=1]=等式左邊

  • 法二:

    利用單位函數暴力拆開:[gcd(i,j)=1]=ε(gcd(i,j))=dgcd(i,j)μ(d)[\gcd(i,j)=1]=\varepsilon(\gcd(i,j))=\sum\limits_{d|\gcd(i,j)}\mu(d)

做題思路&&應用

利用狄利克雷卷積可以解決一系列求和問題。常見做法是使用一個狄利克雷卷積替換求和式中的一部分,然後調換求和順序,最終降低時間複雜度。

經常利用的卷積有μ1=ϵ\mu*1=\epsilonId=φ1\text{Id}=\varphi*1

還是以題爲主吧,但是做的題也會單獨寫題解,畢竟要多水幾篇博客的嘛/huaji

洛谷 P2522 [HAOI2011]Problem b

題目鏈接

我的題解

nn組詢問,每次給出a,b,c,d,ka,b,c,d,k,求x=aby=cd[gcd(x,y)=k]\sum\limits_{x=a}^{b}\sum\limits_{y=c}^{d}[\gcd(x,y)=k]

f(n,m)=i=1nj=1m[gcd(i,j)=k]f(n,m)=\sum\limits_{i=1}^{n}\sum\limits_{j= 1}^{m}[\gcd(i,j)=k]

那麼根據容斥原理,題目中的式子就轉化成了f(b,d)f(b,c1)f(a1,d)+f(a1,c1)f(b,d)-f(b, c - 1) - f(a - 1,d) + f(a - 1, c - 1)

所以我們接下來的問題就轉化爲了如何求ff的值

現在來化簡ff的值

  1. 容易得出原式等價於i=1nkj=1mk[gcd(i,j)=1]\sum\limits_{i = 1}^{\lfloor\frac{n}{k}\rfloor}\sum\limits_{j = 1}^{\lfloor\frac{m}{k}\rfloor}[\gcd(i,j) = 1]

  2. 因爲ϵ(n)=dnμ(d)=[n=1]\epsilon(n) =\sum\limits_{d|n}\mu(d)=[n=1],由此可將原式化爲
    i=1nkj=1mkdgcd(i,j)μ(d)\sum\limits_{i=1}^{\lfloor\frac{n}{k}\rfloor}\sum\limits_{j=1}^{\lfloor\frac{m}{k}\rfloor}\sum\limits_{d|gcd(i,j)}\mu(d)

  3. 改變枚舉對象並改變枚舉順序,先枚舉dd,得
    d=1min(n,m)μ(d)i=1nk[di]j=1mk[dj]\sum\limits_{d=1}^{\min(n,m)}\mu(d)\sum\limits_{i=1}^{\lfloor\frac{n}{k}\rfloor}[d|i]\sum\limits_{j=1}^{\lfloor\frac{m}{k}\rfloor}[d|j]

    也就是說當did|idjd|j時,dgcd(i,j)d|\gcd(i,j)

  4. 易得1nk1\sim \lfloor\frac{n}{k}\rfloor中一共有ndk\lfloor\frac{n}{dk}\rfloordd的倍數,同理1mk1\sim \lfloor\frac{m}{k}\rfloor中一共有mdk\lfloor\frac{m}{dk}\rfloordd的倍數,於是原式化爲d=1min(n,m)μ(d)ndkmdk\sum\limits_{d=1}^{\min(n,m)}\mu(d)\lfloor\frac{n}{dk}\rfloor\lfloor\frac{m}{dk}\rfloor

此時已經可以O(n)O(n)求解,但是過不了,因爲有很多值相同的區間,所以可以用數論分塊來做

先預處理μ\mu,再用數論分塊,複雜度O(n+Tn)O(n+T\sqrt n)

我的代碼每次得分玄學,看評測機心情,建議自己寫

/*
Author:loceaner
*/
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

const int A = 1e6 + 11;
const int B = 1e6 + 11;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;

inline int read() {
	char c = getchar(); int x = 0, f = 1;
	for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
	for( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
	return x * f;
}

int n, a, b, c, d, k, cnt, p[A], mu[A], sum[A];
bool vis[A];

void getmu() {
	int MAX = 50010;
	mu[1] = 1;
	for (int i = 2; i <= MAX; i++) {
		if (!vis[i]) mu[i] = -1, p[++cnt] = i;
		for (int j = 1; j <= cnt && i * p[j] <= MAX; j++) {
			vis[i * p[j]] = true;
			if (i % p[j] == 0) break;
			mu[i * p[j]] -= mu[i];
		}
	}
	for (int i = 1; i <= MAX; i++) sum[i] = sum[i - 1] + mu[i];
}

int work(int x, int y) {
	int ans = 0ll;
	int max = min(x, y);
	for (int l = 1, r; l <= max; l = r + 1) {
		r = min(x / (x / l), y / (y / l));
		ans += (1ll * x / (l * k)) * (1ll * y / (l * k)) * 1ll * (sum[r] - sum[l - 1]); 
	}
	return ans;
}

void solve() {
	a = read(), b = read(), c = read(), d = read(), k = read();
	cout << work(b, d) - work(a - 1, d) - work(b, c - 1) + work(a - 1, c - 1) << '\n';
}

signed main() {
	getmu();
	int T = read();
	while (T--) solve();
	return 0;
}

洛谷 P3455 [POI2007]ZAP-Queries

題目鏈接

我的題解

TT組詢問,每次詢問求

x=1ay=1b[gcd(x,y)=d]\sum\limits_{x=1}^{a}\sum\limits_{y=1}^{b}[\gcd(x,y)=d]

因爲我不喜歡用xyabdx、y、a、b、d,所以一一對應換成ijnmki、j、n、m、k

直接淦式子(太長了CSDN加載不出來於是換成了截圖)
在這裏插入圖片描述

現在就可以每次詢問O(n)O(n)做這道題了

但是跑不過啊,不過顯然可以數論分塊,所以我們就可以O(n)O(\sqrt n)回答每次詢問了

/*
Author:loceaner
*/
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

const int A = 5e5 + 11;
const int B = 1e6 + 11;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;

inline int read() {
	char c = getchar(); int x = 0, f = 1;
	for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
	for( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
	return x * f;
}

int n, m, k, mu[A], p[A], sum[A], cnt;
bool vis[A];

void getmu(int n) {
	mu[1] = 1;
	for (int i = 2; i <= n; i++) {
		if (!vis[i]) p[++cnt] = i, mu[i] = -1;
		for (int j = 1; j <= cnt && i * p[j] <= n; j++) {
			vis[i * p[j]] = 1;
			if (i % p[j] == 0) break;
			mu[i * p[j]] -= mu[i];
		}
	}
	for (int i = 1; i <= n; i++) sum[i] = sum[i - 1] + mu[i];
}

int solve(int n, int m, int k) {
	int ans = 0, maxn = min(n, m);
	for (int l = 1, r; l <= maxn; l = r + 1) {
		r = min(n / (n / l), m / (m / l));
		ans += (sum[r] - sum[l - 1]) * (n / (k * l)) * (m / (k * l));
	}
	return ans;
}

int main() {
	getmu(50000);
	int T = read();
	while (T--) {
		n = read(), m = read(), k = read();
		cout << solve(n, m, k) << '\n';
	}
	return 0;
}

洛谷 P1829 [國家集訓隊]Crash的數字表格 / JZPTAB

題目鏈接

我的題解

i=1nj=1mlcm(i,j)(mod20101009)\sum\limits_{i=1}^{n}\sum\limits_{j=1}^{m}\text{lcm}(i,j)(\bmod 20101009)

容易想到原式等價於

i=1nj=1mijgcd(i,j)\sum\limits_{i=1}^{n}\sum\limits_{j=1}^{m}\frac{i* j}{\gcd(i,j)}

枚舉i,ji,j的最大公約數dd,顯然gcd(id,jd)=1\gcd(\frac id,\frac jd)=1,即id\frac idjd\frac jd互質

i=1nj=1mdi,dj,gcd(id,jd)=1ijd\sum\limits_{i=1}^{n}\sum\limits_{j=1}^m\sum\limits_{d|i,d|j,\gcd(\frac id,\frac jd)=1}\frac{i*j}d

變換求和順序

d=1ndi=1ndj=1md[gcd(i,j)=1]ij\sum\limits_{d=1}^{n}d\sum\limits_{i=1}^{\lfloor\frac{n}{d}\rfloor}\sum\limits_{j=1}^{\lfloor\frac{m}{d}\rfloor}[\gcd(i,j)=1]i*j

sum(n,m)=i=1nj=1m[gcd(i,j)=1]ijsum(n,m)=\sum\limits_{i=1}^{n}\sum\limits_{j=1}^{m}[\gcd(i,j)=1]i*j

對其進行化簡,用ε(gcd(i,j))\varepsilon(\gcd(i,j))替換[gcd(i,j)=1][\gcd(i,j)=1]

i=1nj=1mdgcd(i,j)μ(d)ij\sum\limits_{i=1}^{n}\sum\limits_{j=1}^{m}\sum\limits_{d|\gcd(i,j)}\mu(d)*i*j

轉化爲首先枚舉約數

d=1min(n,m)dindjmμ(d)ij\sum\limits_{d=1}^{\min(n,m)}\sum\limits_{d|i}^{n}\sum\limits_{d|j}^{m}\mu(d)*i*j

i=id,j=jdi=i'*d,j=j'*d,則可以進一步轉化

d=1min(n,m)μ(d)d2i=1ndj=1mdij\sum\limits_{d=1}^{\min(n,m)}\mu(d)*d^2*\sum\limits_{i=1}^{\lfloor\frac{n}{d}\rfloor}\sum\limits_{j=1}^{\lfloor\frac{m}{d}\rfloor}i*j

前半段可以處理前綴和,後半段可以O(1)O(1)求,設

Q(n,m)=i=1nj=1mij=n(n+1)2m(m+1)2Q(n,m)=\sum\limits_{i=1}^{n}\sum\limits_{j=1}^{m}i*j=\frac{n*(n+1)}{2}*\frac{m*(m+1)}{2}

顯然可以O(1)O(1)求解

到現在

sum(n,m)=d=1min(n,m)μ(d)d2Q(nd,md)sum(n,m)=\sum\limits_{d=1}^{\min(n,m)}\mu(d)*d^2*Q(\lfloor\frac nd \rfloor,\lfloor\frac md\rfloor)

可以用數論分塊求解

迴帶到原式中

d=1min(n,m)dsum(nd,md)\sum\limits_{d=1}^{\min(n, m)}d*sum(\lfloor\frac nd \rfloor,\lfloor\frac md\rfloor)

又可以數論分塊求解了

然後就做完啦

/*
Author:loceaner
*/
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define int long long
using namespace std;

const int A = 1e7 + 11;
const int B = 1e6 + 11;
const int mod = 20101009;
const int inf = 0x3f3f3f3f;

inline int read() {
    char c = getchar(); int x = 0, f = 1;
    for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
    for( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
    return x * f;
}

bool vis[A];
int n, m, mu[A], p[B], sum[A], cnt;

void getmu() {
    mu[1] = 1;
    int k = min(n, m);
    for (int i = 2; i <= k; i++) {
        if (!vis[i]) p[++cnt] = i, mu[i] = -1;
        for (int j = 1; j <= cnt && i * p[j] <= k; ++j) {
            vis[i * p[j]] = 1;
            if (i % p[j] == 0) break;
            mu[i * p[j]] = -mu[i];
        }
    }
    for (int i = 1; i <= k; i++) sum[i] = (sum[i - 1] + i * i % mod * mu[i]) % mod;
}

int Sum(int x, int y) { 
	return (x * (x + 1) / 2 % mod) * (y * (y + 1) / 2 % mod) % mod; 
}

int solve2(int x, int y) {
    int res = 0;
    for (int i = 1, j; i <= min(x, y); i = j + 1) {
        j = min(x / (x / i), y / (y / i));
        res = (res + 1LL * (sum[j] - sum[i - 1] + mod) * Sum(x / i, y / i) % mod) % mod;
    }
    return res;
}

int solve(int x, int y) {
    int res = 0;
    for (int i = 1, j; i <= min(x, y); i = j + 1) {
        j = min(x / (x / i), y / (y / i));
        res = (res + 1LL * (j - i + 1) * (i + j) / 2 % mod * solve2(x / i, y / i) % mod) % mod;
    }
    return res;
}

signed main() {
    n = read(), m = read();
    getmu();
    cout << solve(n, m) << '\n';
}

洛谷 P2257 YY的GCD

題目鏈接

給定n,mn,m,求二元組(x,y)(x,y)的個數,滿足1xn,1ym1\leq x\leq n,1\leq y\leq m,且gcd(x,y)gcd(x,y)是素數。

n,m107n,m\leq 10^7,自帶多組數據,至多10410^{4}組數據。

思路與第一題Problem B類似,在這裏不再贅述,只給出代碼= =

#include <cmath> 
#include <cstdio>
#include <cstring> 
#include <iostream>
using namespace std;

const int A = 1e7 + 11; 

inline int read() {
	char c = getchar(); int x = 0, f = 1;
	for ( ; !isdigit(c); c = getchar()) if(c == '-') f = -1; 
	for ( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
	return x * f;
}

bool vis[A];
long long sum[A];
int prim[A], mu[A], g[A], cnt, n, m;

void get_mu(int n) {
    mu[1] = 1;
    for (int i = 2; i <= n; i++) {
        if (!vis[i]) {
            mu[i] = -1;
            prim[++cnt] = i;
        }
        for (int j = 1; j <= cnt && prim[j] * i <= n; j++) {
            vis[i * prim[j]] = 1;
            if (i % prim[j] == 0) break;
            else mu[prim[j] * i] = - mu[i];
        }
    }
    for (int j = 1; j <= cnt; j++)
        for (int i = 1; i * prim[j] <= n; i++) g[i * prim[j]] += mu[i];
    for (int i = 1; i <= n; i++) sum[i] = sum[i - 1] + (long long)g[i];
}

signed main() {
    int t = read();
    get_mu(10000000);
    while (t--) {
        n = read(), m = read();
        if (n > m) swap(n, m);
        long long ans = 0;
        for (int l = 1, r; l <= n; l = r + 1) {
            r = min(n / (n / l), m / (m / l));
            ans += 1ll * (n / l) * (m / l) * (sum[r] - sum[l - 1]);
        }
        cout << ans << '\n';
    }
    return 0;
}

洛谷 P3327 [SDOI2015]約數個數和

題目鏈接

i=1nj=1md(ij)\sum\limits_{i=1}^{n}\sum\limits_{j=1}^{m}d(ij)

d(x)d(x)xx的約數個數和

需要用到

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

證明我也不會

然後自己推導吧,在此不再贅述

/*
Author:loceaner
*/
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

const int A = 5e5 + 11;
const int B = 1e6 + 11;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;

inline int read() {
	char c = getchar(); int x = 0, f = 1;
	for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
	for( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
	return x * f;
}

bool vis[A];
int n, m, p[A], mu[A], cnt, sum[A];
long long g[A], ans;

void getmu(int n) {
	mu[1] = 1;
	for (int i = 2; i <= n; i++) {
		if (!vis[i]) mu[i] = -1, p[++cnt] = i;
		for (int j = 1; j <= cnt && i * p[j] <= n; j++) {
			vis[i * p[j]] = 1;
			if (i % p[j] == 0) break;
			mu[i * p[j]] -= mu[i];
		}
	}
	for (int i = 1; i <= n; i++) sum[i] = sum[i - 1] + mu[i];
	for (int i = 1; i <= n; i++) {
		int ans = 0;
		for (int l = 1, r; l <= i; l = r + 1) {
			r = (i / (i / l));
			ans += 1ll * (r - l + 1) * (i / l);
		}
		g[i] = ans;
	}
}

signed main() {
	int T = read();
	getmu(50000);
	while (T--) {
		n = read(), m = read();
		int maxn = min(n, m);
		ans = 0;
		for (int l = 1, r; l <= maxn; l = r + 1) {
			r = min(n / (n / l), m / (m / l));
			ans += 1ll * (sum[r] - sum[l - 1]) * 1ll * g[n / l] * 1ll * g[m / l];
		}
		cout << ans << '\n';
	}
	return 0;
}

洛谷 P4449 於神之怒加強版

i=1nj=1mgcd(i,j)k(mod1e9+7)\sum_{i=1}^{n}\sum_{j=1}^{m}\gcd(i,j)^k(\bmod 1e9+7)

還是直接淦式子

P=dxP=dx,則原式等於

P=1min(n,m)nPmPdPdkμ(Pd)\sum_{P=1}^{\min(n,m)}\lfloor\frac n{P}\rfloor\lfloor\frac m{P}\rfloor\sum_{d|P}d^k\mu(\frac Pd)

顯然前面的nPmP\lfloor\frac n{P}\rfloor\lfloor\frac m{P}\rfloor部分可以分塊求解。

現在考慮後面的一部分,令

g(n)=dndkμ(nd)g(n)=\sum_{d|n}d^k\mu(\frac nd)

容易得出這個函數是積性函數,所以我們就可以線性篩然後求出其前綴和

然後就做完了

/*
Author:loceaner
莫比烏斯反演
*/
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define int long long
using namespace std;

const int A = 5e6 + 11;
const int B = 1e6 + 11;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;

inline int read() {
	char c = getchar();
	int x = 0, f = 1;
	for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
	for( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
	return x * f;
}

bool vis[A];
int T, n, m, k, f[A], g[A], p[A], cnt, sum[A];

inline int power(int a, int b) {
	int res = 1;
	while (b) {
		if (b & 1) res = res * a % mod;
		a = a * a % mod, b >>= 1;
	}
	return res;
}

inline int mo(int x) {
	if(x > mod) x -= mod;
	return x;
}

inline void work() {
	g[1] = 1;
	int maxn = 5e6 + 1;
	for (int i = 2; i <= maxn; i++) {
		if (!vis[i]) { p[++cnt] = i, f[cnt] = power(i, k), g[i] = mo(f[cnt] - 1 + mod); }
		for (int j = 1; j <= cnt && i * p[j] <= maxn; j++) {
			vis[i * p[j]] = 1;
			if (i % p[j] == 0) { g[i * p[j]] = g[i] * 1ll * f[j] % mod; break; }
			g[i * p[j]] = g[i] * 1ll * g[p[j]] % mod;
		}
	}
	for (int i = 2; i <= maxn; i++) g[i] = (g[i - 1] + g[i]) % mod;
}

inline int abss(int x) {
	while (x < 0) x += mod;
	return x;
}

signed main() {
	T = read(), k = read();
	work();
	while (T--) {
		n = read(), m = read();
		int maxn = min(n, m), ans = 0;
		for (int l = 1, r; l <= maxn; l = r + 1) {
			r = min(n / (n / l), m / (m / l));
			(ans += abss(g[r] - g[l - 1]) * 1ll * (n / l) % mod * (m / l) % mod) %= mod;
		}
		ans = (ans % mod + mod) % mod;
		cout << ans << '\n';
	}
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章