题目大意

计算

$$ \sum_{i=1}^n \sum_{j=1}^m \operatorname{lcm}(i, j) $$

分析

先化 $\gcd$ 出来

$$ ans = \sum_{i=1}^n \sum_{j=1}^m \frac{ij}{\gcd(i, j)} $$

显然套 Mobius 反演,朝着那个方向化就行。

$$ \begin{aligned} ans &= \sum_{d=1}^n \sum_{i=1}^n \sum_{j=1}^m \frac{ij}{d} [\gcd(i, j) = d] \\ &= \sum_{d=1} d \sum_{i=1}^{n / d} \sum_{j=1}^{m / d} ij [\gcd(i, j) = 1] \\ &= \sum_{d=1} d \sum_{x=1}^{\min(n/d, m/d)} x^2\mu(x) S_1 \left(\left\lfloor \frac{m}{dx} \right\rfloor \right) S_1 \left(\left\lfloor \frac{n}{dx} \right\rfloor \right) \end{aligned} $$

其中 $x^2 \mu(x)$ 可以线性筛预处理,后者可以整除分块嵌套一下。

Z iv2 = Z(2).inv();

Z S1(Z x) {
	return x * (x + 1) * iv2;
}

Z sol1(int md, int nd) {
	Z ans = 0;
	for (int l = 1, r; l <= min(md, nd); l = r + 1) {
		r = min(md / (md / l), nd / (nd / l));
		ans += (smu[r] - smu[l - 1]) * S1(nd / l) * S1(md / l);
	}
	return ans;
}

int main() {
	int n, m;
	cin >> n >> m;
	Z ans = 0;
	Euler(max(n, m) + 10);
	for (int l = 1, r; l <= min(n, m); l = r + 1) {
		r = min(n / (n / l), m / (m / l));
		ans += (S1(r) - S1(l - 1)) * sol1(n / l, m / l);
	}
	cout << ans;
	return 0;
}

全部代码请看:Luogu/1x/P1829.cpp