题目大意
在 $n \times m$ 的花园中,设 $(0, 0) \to (i, j)$ 之间的格点数为 $k$,则 $(i, j)$ 的贡献为 $2k+1$。求整个花园的累计贡献。
分析
首先,格点数为 $\gcd(i, j) - 1$,不要拿 $\min(n/i, m/j)$ 去算,算不清楚的。
因此答案为
$$ ans = \sum_{i=1}^n \sum_{j=1}^m (2\gcd(i, j) - 1) $$
由欧拉反演
$$ \sum_{d \mid n} \varphi(d) = n $$
因此
$$ \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。