P6810 「MCOI-02」Convex Hull 凸包 莫比乌斯反演

P6810 「MCOI-02」Convex Hull 凸包

题目链接

​ 莫比乌斯反演。

​ 要化简这个式子:\(\displaystyle \sum_{i = 1}^{n} \sum_{j = 1}^{m}r(i)r(j)r(gcd(i, j))\)\(r(x)\)代表\(x\)的约数个数。

甩链接

​ 可以化简为:\(\displaystyle \sum_{T = 1}^{min(n, m)} \sum_{x = 1}^{\frac{n}{T}} \sum_{y = 1}^{\frac{m}{T}} r(xT)r(yT)\)

​ 用前缀和优化一下就好。

​ 我卡在了这一步:\(r * \mu = 1\),约数个数卷上莫比乌斯函数为1。

#include <bits/stdc++.h>

using namespace std;

inline long long read() {
    long long s = 0, f = 1; char ch;
    while(!isdigit(ch = getchar())) (ch == '-') && (f = -f);
    for(s = ch ^ 48;isdigit(ch = getchar()); s = (s << 1) + (s << 3) + (ch ^ 48));
    return s * f;
}

const int N = 2e6 + 5;
int n, m, p, cnt, ans;
int r[N], x[N], y[N], num[N], prime[N], is_prime[N];

void make_r(int x) {
    r[1] = 1;
    for(int i = 2;i <= x; i++) {
        if(!is_prime[i])
            prime[++cnt] = i, r[i] = 2, num[i] = 1;
        for(int j = 1;j <= cnt && i * prime[j] <= x; j++) {
            is_prime[i * prime[j]] = 1;
            if(!(i % prime[j])) {
                num[i * prime[j]] = num[i] + 1;
                r[i * prime[j]] = r[i] / (num[i] + 1) * (num[i] + 2);
                break;
            }
            num[i * prime[j]] = 1;
            r[i * prime[j]] = r[i] * r[prime[j]];
        }
    }
}

int main() {

    n = read(); m = read(); p = read();

    make_r(max(n, m));

    // for(int i = 1;i <= min(n, m); i++) cout << i << " " << r[i] << endl;

    for(int T = 1;T <= n; T++)
        for(int i = 1;i <= n / T; i++) x[T] = (x[T] + r[i * T]) % p;

    for(int T = 1;T <= m; T++)
        for(int i = 1;i <= m / T; i++) y[T] = (y[T] + r[i * T]) % p;

    for(int T = 1;T <= min(n, m); T++) 
        ans = (ans + 1ll * x[T] * y[T] % p) % p;

    printf("%d", ans);

    return 0;
}
posted @ 2020-09-14 21:39  C锥  阅读(135)  评论(0编辑  收藏  举报