1 条题解

  • 0
    @ 2024-4-3 16:25:41
    #include <bits/stdc++.h>
    using namespace std;
    #define int long long
    #define endl "\n"
    const int N = 50010;
    
    // 线性筛法求莫比乌斯函数(枚举约数)
    int mu[N], sum[N]; // 莫比乌斯函数的前缀和
    int primes[N], cnt;
    bool st[N];
    void get_mobius(int n) {
        mu[1] = 1;
        for (int i = 2; i <= n; i++) {
            if (!st[i]) {
                primes[cnt++] = i;
                mu[i] = -1;
            }
            for (int j = 0; primes[j] * i <= n; j++) {
                int t = primes[j] * i;
                st[t] = true;
                if (i % primes[j] == 0) {
                    mu[t] = 0;
                    break;
                }
                mu[t] = -mu[i];
            }
        }
        // 维护莫比乌斯函数前缀和
        for (int i = 1; i <= n; i++) sum[i] = sum[i - 1] + mu[i];
    }
    
    signed main() {
        // 筛法求莫比乌斯函数
        get_mobius(N - 1);
    
        int T;
        cin >> T;
    
        while (T--) {
            int a, b, d;
            cin >> a >> b >> d;
            // 套路啊,满满的套路,直接先用最大公约数a/gcd(a,b)=a',b/gcd(a,b)=b',映射到a',b'
            a /= d, b /= d;
    
            // n为 min(a', b')
            int n = min(a, b);
    
            int res = 0;
    
            // l r, 是每一段的左右边界
            // 每次只能取较小的那个上界作为这一段的右端点r
            // 然后下次迭代时下一段的左端点就是r + 1
            for (int l = 1, r; l <= n; l = r + 1) { // 分块大法
                r = min(n, min(a / (a / l), b / (b / l)));
                res += (sum[r] - sum[l - 1]) * (a / l) * (b / l);
            }
            cout << res << endl;
        }
    }
    
    
  • 1

信息

ID
126
时间
1000ms
内存
128MiB
难度
10
标签
递交数
5
已通过
4
上传者