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;
}
posted @ 2020-09-13 21:21  Gensokyo_Alice  阅读(80)  评论(0编辑  收藏  举报