P1447 [NOI2010]能量采集
显然(我觉得不),对于点 \((i, j)\) 与 \((0, 0)\) 的连线,连线上点的数量是 \(\gcd(i, j)\)
那么问题转化为 \(\displaystyle \sum_{i=1}^{N} \sum_{j=1}^{M} (2 \cdot (i, j) -1)\)
那么我们可以设(一下均令 \(N \le M\) ) \(f_{x}\) 为 \(x\) 及其倍数 在上述和式中作为 \((i, j)\) 的出现次数。令 \(g_{x}\) 为 恰好\(x\) 在和式中作为 \((i, j)\) 出现的次数。
那么可得 \(\displaystyle \sum_{i=1}^{\lfloor \tfrac{N}{d} \rfloor} f_{i} = \lfloor \tfrac{N}{d} \rfloor \cdot \lfloor \tfrac{M}{d} \rfloor\)
因为容斥\(g_{x} = f_{x} - \displaystyle \sum_{i=2}^{\lfloor \tfrac{N}{x} \rfloor} f_{i \cdot x}\)
然后暴力计算,复杂度 \(O(NlogN)\)
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
typedef long long ll;
const ll MAXN = 1000010;
ll vis[MAXN], N, M, ans;
int main() {
scanf("%lld%lld", &N, &M);
if (N > M) swap(N, M);
for (ll d = 1; d <= N; d++) {
vis[d] = (N / d) * (M / d);
}
for (ll i = N; i >= 1; i--) {
for (ll j = 2; j <= N / i; j++) vis[i] -= vis[i * j];
ans += (vis[i] * (i * 2 - 1));
}
printf("%lld\n", ans);
return 0;
}
希望我们都有一个光明的未来