题目大意

计算

$$ \sum_{i=1}^n \sum_{j=1}^m \sigma_1(\gcd(i, j)) [\sigma_1(\gcd(i, j)) \leqslant a] $$

分析

若不考虑 $a$ 的限制,就是非常套路的 Mobius 反演

$$ ans = \sum_{d=1} \sigma_1(d) [d \leqslant a] \sum_{x=1} \mu(x) \left\lfloor \frac{n}{dx} \right\rfloor \left\lfloor \frac{m}{dx} \right\rfloor $$

但是这个 $a$ 的限制比较头疼。考虑 $y=dx$ 代换,有

$$ ans = \sum_{y=1} \left\lfloor \frac{n}{y} \right\rfloor \left\lfloor \frac{m}{y} \right\rfloor \sum_{d \mid y} \sigma_1(d) \mu\left(\frac{y}{d}\right) [d \leqslant a] $$

因此我们可以将询问対 $a$ 排序,后者使用树状数组维护。

int main() {
	Euler(N);

	int T;
	cin >> T;
	vector<i4> v(T);
	for (int i = 0; i < T; i++) {
		int n, m, a;
		cin >> n >> m >> a;
		v[i] = {n, m, a, i};
	}
	sort(v.begin(), v.end(), [](const i4 &l, const i4 &r) {
		return std::get<2>(l) < std::get<2>(r);
	});

	fwtree<ll> tr(N);

	auto add = [&](int x) {
		auto [sgm, q] = sigma[x];
		for (int i = 1; i * q < N; i++) {
			tr.add(i * q, sgm * mu[i]);
		}
	};

	int pos = 1;
	vector<ll> ret(T);
	for (auto [n, m, a, i] : v) {
		while (sigma[pos].first <= a) {
			add(pos++);
		}
		for (int l = 1, r; l <= min(n, m); l = r + 1) {
			r = min(n / (n / l), m / (m / l));
			ret[i] += tr.sum(l, r) * ll(n / l) * ll(m / l) % P;
		}
	}
	for (auto ai : ret) {
		cout << ai % P << '\n';
	}

	return 0;
}

全部代码请看:Luogu/3x/P3312.cpp