题解: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;
}

浙公网安备 33010602011771号