题解 [SDOI2018]旧试题
蒟蒻语
第 50 道黑题,写篇题解祭一下 /cy
蒟蒻解
\( \begin{aligned} &\sum\limits_{i=1}^{A} \sum\limits_{j=1}^{B} \sum\limits_{k=1}^{C} d(i, j, k)\\ &= \sum\limits_{i=1}^{A} \sum\limits_{j=1}^{B} \sum\limits_{k=1}^{C} \sum\limits_{x|i} \sum\limits_{y|j} \sum\limits_{z|k} [\gcd(x, y) = 1][\gcd(y, z) = 1][\gcd(z, x) = 1]\\ &= \sum\limits_{x=1}^{A} \sum\limits_{y=1}^{B} \sum\limits_{z=1}^{C} [\gcd(x, y) = 1][\gcd(y, z) = 1][\gcd(z, x) = 1] \left\lfloor\frac{A}{x}\right\rfloor \left\lfloor\frac{B}{y}\right\rfloor \left\lfloor\frac{C}{z}\right\rfloor\\ &= \sum\limits_{d_1=1}^{A} \mu(d_1)\sum\limits_{d_2=1}^{B} \mu(d_2) \sum\limits_{d_3=1}^{C} \mu(d_3) \sum\limits_{x=1}^{ \left\lfloor\frac{A}{\operatorname{lcm}(d_1,d_2)}\right\rfloor} \left\lfloor\frac{A}{\operatorname{lcm}(d_1,d_2)x}\right\rfloor \sum\limits_{y=1}^{ \left\lfloor\frac{B}{\operatorname{lcm}(d_2,d_3)}\right\rfloor} \left\lfloor\frac{B}{\operatorname{lcm}(d_2,d_3)y}\right\rfloor \sum\limits_{z=1}^{ \left\lfloor\frac{C}{\operatorname{lcm}(d_3,d_1)}\right\rfloor} \left\lfloor\frac{C}{\operatorname{lcm}(d_3,d_1)z}\right\rfloor\\ \end{aligned} \)
(设 \(Max = \max (A, B, C)\))
考虑哪些三元组会有贡献。
- \(\mu(d_1), \mu(d_2), \mu(d_3)\) 不为 \(0\)。
- \(\operatorname{lcm}(d_1,d_2) , \operatorname{lcm}(d_2,d_3), \operatorname{lcm}(d_3,d_1) \le Max\)
把一个数看成一个点。
首先我们把 \(\mu(x)\) 为 \(0\) 的点排除在外。
然后把 \(\operatorname{lcm}(x, y) \le Max\) 的点连接起来。
然后再做一遍三元环计数就好了,暴力枚举每一个三元环统计答案。为了更快地统计答案,可以先把边定向。
这样的时间复杂度是 \(O(m \sqrt m)\) 的。( \(m\) 是边数)
事实上,边数最多只有 \(821535\) 条 (用蒟蒻劣质的程序算出来)
因此这道题就被解决了
蒟蒻码
#include<bits/stdc++.h>
#define L(i, j, k) for(int i = j; i <= k; i++)
#define R(i, j, k) for(int i = j; i >= k; i--)
#define ll long long
using namespace std;
const int N = 1e5 + 7;
const int M = 1e6 + 7;
const int mod = 1e9 + 7;
bool Prime[N];
int tot, P[N >> 3], mu[N];
void xxs() {
mu[1] = 1;
L(i, 2, 1e5) {
if(!Prime[i]) P[++tot] = i, mu[i] = -1;
for(int j = 1; P[j] * i <= 1e5 && j <= tot; j++) {
Prime[P[j] * i] = 1;
if(i % P[j] == 0) {
mu[P[j] * i] = 0;
break;
}
mu[P[j] * i] = -mu[i];
}
}
}
vector<int> ve[N];
unordered_map<int, bool> mp[N];
int T, Max, A, B, C, ans, p[N];
int sA[M], sB[M], sC[M], cnt, deg[N];
int gcd(int x, int y) { return x == 0 ? y : gcd(y % x, x); }
ll lcm(int x, int y) { return 1ll * x / gcd(x, y) * y; }
int ta, tb, tc, sum;
void dh(int a, int b, int c) {
(sum += 1ll * p[a / ta] * p[b / tb] % mod * p[c / tc] % mod) %= mod;
}
void get(int a, int b, int c) {
sum = 0;
if(a == b && b == c) dh(A, B, C);
else if(a == b || b == c || c == a) dh(A, B, C), dh(C, A, B), dh(B, C, A);
else dh(A, B, C), dh(A, C, B), dh(B, A, C), dh(B, C, A), dh(C, A, B), dh(C, B, A);
(ans += (mu[a] * mu[b] * mu[c] * sum % mod + mod) % mod) %= mod;
}
int vis[N];
void js() {
L(i, 1, cnt) {
int &u = sA[i], &v = sB[i];
if(deg[u] > deg[v]) swap(u, v);
else if(deg[u] == deg[v] && u > v) swap(u, v);
ve[u].push_back(i);
}
L(i, 1, Max) {
for(int j : ve[i]) vis[sB[j]] = sC[j];
for(int j : ve[i]) for(int k : ve[sB[j]])
if(vis[sB[k]]) ta = vis[sB[k]], tb = sC[j], tc = sC[k], get(i, sB[j], sB[k]);
for(int j : ve[i]) vis[sB[j]] = 0;
}
}
void getans(int x) {
for(int l = 1, r; l <= x; l = r + 1) {
r = (x / (x / l));
(p[x] += 1ll * (r - l + 1) * (x / l) % mod) %= mod;
}
}
int main() {
scanf("%d", &T);
xxs();
L(i, 1, 1e5) getans(i);
while(T--) {
scanf("%d%d%d", &A, &B, &C);
ans = cnt = 0;
Max = max(max(A, B), C);
R(i, Max, 1) for(int j = i; j <= Max; j += i) {
if(!mu[j]) continue;
for(int k = j; k <= 1ll * Max * i / j; k += i) {
if(!mu[k]) continue;
if(!mp[j][k]) ++cnt, sA[cnt] = j, sB[cnt] = k, sC[cnt] = j / i * k, deg[j] ++, deg[k] ++, mp[j][k] = 1;
}
}
js();
L(i, 1, Max) ve[i].clear(), mp[i].clear(), deg[i] = 0;
printf("%d\n", (ans + mod) % mod);
}
return 0;
}