【[SDOI2018]旧试题】

一道很有趣的题目。
题目大意:求

[sum_{i=1}^A sum_{j=1}^B sum_{k=1}^C sigma_0(ijk) ]

因为

[sigma_0(ijk)=sum_{p|i}sum_{q|j}sum_{h|k}[epsilon( ext{gcd}(p,q))][epsilon( ext{gcd}(p,h))][epsilon( ext{gcd}(q,h))] ]

所以原式=

[sum_{i=1}^Asum_{j=1}^Bsum_{k=1}^Csum_{p|i}sum_{q|j}sum_{h|k}[epsilon( ext{gcd}(p,q))][epsilon( ext{gcd}(p,h))][epsilon( ext{gcd}(q,h))] ]

交换枚举顺序,枚举因数

[sum_{p=1}^Asum_{q=1}^Bsum_{h=1}^C lfloor frac{A}{p} floor lfloor frac{B}{q} floor lfloor frac{C}{h} floor [epsilon( ext{gcd}(p,q))][epsilon( ext{gcd}(p,h))][epsilon( ext{gcd}(q,h))]]

把后面那团( ext{gcd})(mu)函数换掉

[sum_{p=1}^Asum_{q=1}^Bsum_{h=1}^C sum_{x| ext{gcd}(p,q)}mu(x) sum_{y| ext{gcd}(p,h)} mu(y) sum_{z| ext{gcd}(q,h)}mu(z) ]

再换一下枚举顺序

[sum_{x=1}^{ ext{min(A,B)}}mu(x) sum_{y=1}^{ ext{min}(A,C)}mu(y) sum_{z=1}^{ ext{min}(B,C)}mu(z) sum_{x|p & & y|p} lfloor frac{A}{p} floor sum_{x|q & & z|q} lfloor frac{B}{q} floor sum_{y | h & & z|h} lfloor frac{C}{h} floor ]

[sum_{x=1}^{ ext{min(A,B)}}mu(x) sum_{y=1}^{ ext{min}(A,C)}mu(y) sum_{z=1}^{ ext{min}(B,C)}mu(z) sum_{ ext{lcm}(x,y)|p} lfloor frac{A}{p} floor sum_{ ext{lcm}(x,z)|q} lfloor frac{B}{q} floor sum_{ ext{lcm}(y,z)|h} lfloor frac{C}{h} floor ]

然后我们发现这个式子其实不一样的地方只有两部分...
形如(sum limits_{a|b}^c lfloor frac{c}{b} floor)的那三项可以(mathcal{O}(n log n))预处理出来。
接下来才是这道题的精髓。
(mathcal{O}(n^3))枚举三元组((x,y,z))的同时,我们可以发现有很多时候他们的情况是(0)
1:(mu(x)=0)(mu(y)=0)(mu(z)=0)
2:若(sum limits_{a|b}^c lfloor frac{c}{b} floor)中的(a)大于(c),则这个式子的贡献一定为(0),也就是说当( ext{lcm}(x,y) geq A)( ext{lcm}(x,z) geq B)( ext{lcm}(y,z) geq C)时,这个式子的贡献一定为(0)
于是我们就可以枚举最大公约数(g),使得(u=i imes g,v = j imes g, mu(u) eq 0,mu(v) eq 0)并保证(i)(j)互质且( ext{lcm}(u,v)=i imes j imes g leq ext{max}(A,B,C)),连边((u,v)),最后统计三元环的时候顺便计数就好了。
因为(mathsf{s{color{red}hadowice1984}})大佬告诉我们边数最多只有(760741)条,所以(m sqrt m)是可过的。
代码:

#include <bits/stdc++.h>

typedef long long ll;
const int N = 1e5 + 200;
const ll mod = 1e9 + 7;
typedef std::pair<int, int> pii;

int n, m, i, j, k, prim_tot, T, A, B, C, mx, mn, cnte;
ll _1[N], _2[N], _3[N];
int vis[N], deg[N];
int mu[N], prim[N]; 
bool _vis[N];
ll ans;

inline void sieve(int n) {
  mu[1] = 1;
  for (int i = 2; i <= n; i++) {
    if (!_vis[i]) prim[++prim_tot] = i, mu[i] = -1;
    for (int j = 1; j <= prim_tot && i * prim[j] <= n; j++) {
      _vis[i * prim[j]] = 1;
      if (i % prim[j] == 0) break;
      else mu[i * prim[j]] = -mu[i];
    }
  }
}

struct edge {
  int u, v, w;
  edge() { u = v = w = 0; }
  edge(int _u, int _v, int _w) {
    u = _u, v = _v, w = _w;
  }
} edges[N << 4];

std::vector<pii> G[N];

inline void init() {
  scanf("%d %d %d", &A, &B, &C), ans = 0, cnte = 0;
  mx = std::max(std::max(A, B), C);
  mn = std::min(std::min(A, B), C);
  for (int i = 1; i <= mx; i += 8) {
    _1[i] = _1[i + 1] = _1[i + 2] = _1[i + 3] = _1[i + 4] = _1[i + 5] = _1[i + 6] = _1[i + 7] = 0;
    _2[i] = _2[i + 1] = _2[i + 2] = _2[i + 3] = _2[i + 4] = _2[i + 5] = _2[i + 6] = _2[i + 7] = 0;
    _3[i] = _3[i + 1] = _3[i + 2] = _3[i + 3] = _3[i + 4] = _3[i + 5] = _3[i + 6] = _3[i + 7] = 0;
    deg[i] = deg[i + 1] = deg[i + 2] = deg[i + 3] = deg[i + 4] = deg[i + 5] = deg[i + 6] = deg[i + 7] = 0;
  }
  for (int i = 1; i <= mx; i++) G[i].clear();
  for (int i = 1; i <= A; i++) {
    for (int j = i; j <= A; j += i)
      _1[i] += A / j;
  }
  for (int i = 1; i <= B; i++) {
    for (int j = i; j <= B; j += i) 
      _2[i] += B / j;
  }
  for (int i = 1; i <= C; i++) {
    for (int j = i; j <= C; j += i)
      _3[i] += C / j;
  }
}
inline void solve() {
  for (int i = 1; i <= mn; i++) {
    if (mu[i]) ans += 1ll * mu[i] * mu[i] * mu[i] * _1[i] * _2[i] * _3[i];
  }
  for (int g = 1; g <= mx; g++) {
    for (int i = 1; i * g <= mx; i++) {
      if (!mu[i * g]) continue;
      for (int j = i + 1; 1ll * i * j * g <= mx; j++) {
        if (mu[j * g] && std::__gcd(i, j) == 1) {
          int u = i * g, v = j * g, lcm = i * j * g;
          int p = mu[u] * mu[u] * mu[v], q = mu[u] * mu[v] * mu[v];
          ans += p * (_1[u] * _2[lcm] * _3[lcm] + _1[lcm] * _2[u] * _3[lcm] + _1[lcm] * _2[lcm] * _3[u]);
          ans += q * (_1[v] * _2[lcm] * _3[lcm] + _1[lcm] * _2[v] * _3[lcm] + _1[lcm] * _2[lcm] * _3[v]);
          deg[u]++, deg[v]++;
          edges[++cnte] = edge(u, v, lcm);
        }
      }
    }
  }
  for (int i = 1; i <= cnte; i++) {
    int u = edges[i].u, v = edges[i].v, w = edges[i].w;
    if (deg[u] < deg[v] || (deg[u] == deg[v] && u > v)) std::swap(u, v);
    G[u].push_back(std::make_pair(v, w));
  }
  for (int k = 1; k <= mx; k++) {
    if (!mu[k]) continue;
    int SZ = G[k].size();
    for (int i = 0; i < SZ; i++) vis[G[k][i].first] = G[k][i].second;
    for (int i = 0; i < SZ; i++) {
      int v = G[k][i].first, w = G[k][i].second;
      if (!mu[v]) continue;
      for (int j = 0, _SZ = G[v].size(); j < _SZ; j++) {
        int vv = G[v][j].first;
        if (!vis[vv]) continue;
        int wyz = G[v][j].second, wxz = vis[vv], mmu = mu[k] * mu[v] * mu[vv];
        if (!mmu) continue;
        ans += mmu * (_1[w] * _2[wyz] * _3[wxz] + _1[w] * _2[wxz] * _3[wyz] 
                    + _1[wyz] * _2[w] * _3[wxz] + _1[wyz] * _2[wxz] * _3[w]
                    + _1[wxz] * _2[w] * _3[wyz] + _1[wxz] * _2[wyz] * _3[w]);
      }
    }
    for (int i = 0; i < SZ; i++) vis[G[k][i].first] = 0;
  }
  printf("%lld
", ans % mod);
}

int main() {
  sieve(100000);
  scanf("%d", &T);
  while (T--) init(), solve();
  return 0;
}

原文地址:https://www.cnblogs.com/Sai0511/p/12389708.html