题解:CF1712E2 LCM Sum (hard version)

CF1712E2 LCM Sum (hard version)

Description

\(T(T\le 10^5)\) 组测试数据,每次给定 \(l,r(\le 2\times 10^5)\),求 \([l,r]\) 中三元组 \((i,j,k)\) 的对数,满足 \(lcm(i,j,k) \ge i+j+k\)

Solution

\(i<j<k\)

若正着统计没什么思路,我们可以反着来,也就是容斥,求 \(lcm(i,j,k) < i+j+k\) 的对数。

容易发现 \(lcm(i,j,k) < 3k\),又因为 \(lcm\) 必须是 \(k\) 的倍数,所以分两种情况讨论。

  • \(lcm(i,j,k) = k\)

    • 这个时候 \(i,j\) 只要是 \(k\) 的约数,就能满足 \(i+j+k > lcm(i,j,k)\)

    • \(d(k)\) 表示 \(k\) 的约数个数,那么对于一个 \(k\),满足条件的 \(i,j\) 数量为 \(C_{d_k-1}^{2}\)\(-1\) 是因为不能选 \(k\) 自己。

    • 那么我们把询问离线,按照 \(l\) 升序排序,每次把 \(i\in[上一个询问的 l,当前 l)\)\(d(i)\) 全部减 \(1\),然后用树状数组维护前缀的组合数的和即可。简单推一下式子即可算出,\(d(i)\) 减去 \(1\) 相当于对应的组合数减去 \((d(i)-1)\)(这里的 \(d(i)\) 是没减 \(1\) 之前的),当然要特判 \(d(i)\) 是否等于 \(0\)

  • \(lcm(i,j,k) = 2k\)

    • 这里就非常奇妙了,如果没想到怎么推,那只能靠打表发现(可能我不知道有其他做法)。

    • 首先我们要求 \(i + j > k\)

    • 由于 \(i,j\)\(2k\) 的约数,那么我们设 \(ai = 2k\)\(bj = 2k\),显然 \(2<b<a\)

    • 那么 \(\frac{2k}{a} + \frac{2k}{b} > k\)\(\frac{2}{a} + \frac{2}{b} > 1\)

    • 又因为 \(\frac{2}{b} > \frac{2}{a}\)(根据 \(b < a\)),

    • 得到 \(\frac{2}{b} > \frac{1}{2}\),解得 \(b=3\)

    • 代入原式,得 \(a=4\)\(a=5\)

    • 于是可以算出 \(i:j:k = 3:4:6\)\(i:j:k = 6:10:15\)

    • 那么我们只需要求出 \([l,r]\) 中有多少个这样的三元组的倍数即可。

      • 第一种,\(\max(0, \frac{r}{6} - \frac{l-1}{3})\)

      • 第二种,\(\max(0, \frac{r}{15} - \frac{l-1}{6})\)

那么最后把两种情况的答案相加,并用 \(C_{r-l+1}^{3}\) 减去即可。

Code

#include <bits/stdc++.h>
using namespace std;
using LL = long long;
using ULL = unsigned long long;
using PII = pair<int, int>;

const int N = 2e5 + 5;

struct Query {
    int l, r, id;
} Q[N];
int cnt[N];
LL ans[N];

struct BT {
    int n;
    LL a[N];

    void init(int _n) {
        n = _n;
        for (int i = 1; i <= n; i++) a[i] = 0;
    }

    void add(int x, LL v) {
        for (; x <= n; x += (x & -x)) a[x] += v;
    }

    LL sum(int x) {
        LL ans = 0;
        for (; x; x -= (x & -x)) ans += a[x];
        return ans;
    }

    LL sum(int l, int r) {
        return sum(r) - sum(l - 1);
    }
} bt;

int main() {
    int q;
    cin >> q;
    for (int i = 1; i <= q; i++) {
        cin >> Q[i].l >> Q[i].r;
        Q[i].id = i;
    }
    sort(Q + 1, Q + 1 + q, [&] (auto a, auto b) { return a.l < b.l; });
    for (int i = 1; i <= 2e5; i++) {
        for (int j = 2; j <= 2e5 / i; j++) {
            cnt[i * j]++;
        }
    }
    bt.init(2e5);
    for (int i = 1; i <= 2e5; i++) {
        bt.add(i, (LL)cnt[i] * (cnt[i] - 1) / 2);
    }
    int lst = 1;
    for (int i = 1; i <= q; i++) {
        for (int j = lst; j < Q[i].l; j++) {
            for (int k = 2; k <= 2e5 / j; k++) {
                if (cnt[j * k]) {
                    bt.add(j * k, -cnt[j * k] + 1);
                    cnt[j * k]--;
                }
            }
        }
        ans[Q[i].id] -= bt.sum(Q[i].l, Q[i].r);
        ans[Q[i].id] -= (LL)max(0, Q[i].r / 6 - (Q[i].l - 1) / 3);
        ans[Q[i].id] -= (LL)max(0, Q[i].r / 15 - (Q[i].l - 1) / 6);
        LL len = Q[i].r - Q[i].l + 1;
        ans[Q[i].id] += len * (len - 1) * (len - 2) / 6;
        lst = Q[i].l;
    }
    for (int i = 1; i <= q; i++) cout << ans[i] << '\n';
    return 0;
}
posted @ 2025-02-19 22:32  chenwenmo  阅读(17)  评论(0)    收藏  举报