题目大意

n×mn \times m 的花园中,设 (0,0)(i,j)(0, 0) \to (i, j) 之间的格点数为 kk,则 (i,j)(i, j) 的贡献为 2k+12k+1。求整个花园的累计贡献。

分析

首先,格点数为 gcd(i,j)1\gcd(i, j) - 1,不要拿 min(n/i,m/j)\min(n/i, m/j) 去算,算不清楚的。

因此答案为

ans=i=1nj=1m(2gcd(i,j)1) ans = \sum_{i=1}^n \sum_{j=1}^m (2\gcd(i, j) - 1)

由欧拉反演

dnφ(d)=n \sum_{d \mid n} \varphi(d) = n

因此

ans=2i=1nj=1mdgcd(i,j)φ(d)nm=2d=1φ(d)ndmdnm \begin{aligned} ans &= 2 \sum_{i=1}^n \sum_{j=1}^m \sum_{d \mid \gcd(i, j)} \varphi(d) - nm\\ &= 2\sum_{d=1}\varphi(d) \left\lfloor \frac{n}{d}\right\rfloor \left\lfloor \frac{m}{d}\right\rfloor - nm \end{aligned}

整除分块即可。

int main() {
	int n, m;
	cin >> n >> m;
	int x = min(n, m);
	Euler(x + 1);

	vector<ll> sphi(x + 1);
	for (int i = 1; i <= x; i++) {
		sphi[i] = sphi[i - 1] + phi[i];
	}

	ll ans = 0;
	for (int l = 1, r; l <= x; l = r + 1) {
		r = min(n / (n / l), m / (m / l));
		ans += 1ll * (sphi[r] - sphi[l - 1]) * (n / l) * (m / l);
	}
	cout << ans * 2 - 1ll * n * m;
	return 0;
}

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