loj#6076「2017 山東一輪集訓 Day6」三元組 莫比烏斯反演 + 三元環計數

題目大意:c++

給定\(a, b, c\),求\(\sum \limits_{i = 1}^a \sum \limits_{j = 1}^b \sum \limits_{k = 1}^c [(i, j) = 1][(j, k) = 1][(i, k) = 1]\)算法

$a, b, c \leq 5*10^4 $spa


首先莫比烏斯反演code

$Ans = \sum \limits_{i = 1}^a \sum \limits_{j = 1}^b \sum \limits_{k = 1}^c [(i, j) = 1][(j, k) = 1][(i, k) = 1] $ci

\(= \sum \limits_{i} \sum \limits_{j} \sum \limits_{k} \sum \limits_{x |i \;x|j} \mu(x) \sum \limits_{y|j\;y|k} \mu(y) \sum \limits_{z |i\;z|k} \mu(z)\)it

\(= \sum \limits_{x} \sum \limits_{y} \sum \limits_{z} \mu(x) \mu(y) \mu(z) \frac{A}{lcm(x, y)} \frac{B}{lcm(x, z)} \frac{C}{lcm(y, z)}\)io

那麼考慮計算這個式子class

注意到其實有效的三元組\((x, y, z)\)是十分稀少的gc

咱們考慮用一種高效的辦法來找到全部的三元組im

三元環計數是一個十分便利的算法

若是\(\mu(u), \mu(v) \neq 0, lca(u, v) \leq C\),那麼咱們連邊\((u, v)\)

怎麼連邊呢?

咱們先枚舉\(lca(u, v)\),而後枚舉\(u\),以後再枚舉\(gcd(u, v)\)判斷便可

對於有兩個數相同的狀況和三個數相同的狀況進行特判便可

複雜度不會算,反正跑的挺快的

ps:我怎麼感受dfs也能過呢?


#include <bits/stdc++.h>
using namespace std;

#define mp make_pair
#define pii pair <int, int>

#define ri register int
#define rep(io, st, ed) for(ri io = st; io <= ed; io ++)
#define drep(io, ed, st) for(ri io = ed; io >= st; io --)

const int sid = 5e4 + 5;
const int cid = 2e6 + 5;
const int mod = 1e9 + 7;
    
inline void inc(int &a, int b) { a += b; if(a >= mod) a -= mod; }
inline int mul(int a, int b) { return 1ll * a * b % mod; }
    
int a, b, c, id, ans, tot;
int mu[sid], pr[sid], nop[sid];
int eu[cid], ev[cid], ew[cid], d[sid], vis[sid], vv[sid];
vector <pii> go[sid];
vector <int> fac[sid];
    
inline void Init() {
    mu[1] = 1;
    for (int i = 2; i <= 50000; i ++) {
        if (!nop[i]) { pr[++ tot] = i; mu[i] = mod - 1; }
        for (int j = 1; j <= tot; j ++) {
            int p = i * pr[j]; 
            if(p > 50000) break; nop[p] = 1;
            if(i % pr[j] == 0) break; if(mu[i]) mu[p] = mod - mu[i];
        }
    }
    
    for (ri i = 1; i <= tot; i ++)
    for (ri j = pr[i]; j <= 50000; j += pr[i])
        fac[j].push_back(pr[i]);
}
    
inline int gcd(int a, int b) { return b ? gcd(b, a % b) : a; }
inline int lcm(int a, int b) { return 1ll * a * b / gcd(a, b);}
    
inline void calc() {
    if(c < a) swap(a, c);
    if(c < b) swap(b, c);
    if(b < a) swap(a, b);
    
    for (ri x = 1; x <= a; x ++) // x = y = z
    if(mu[x]) inc(ans, mul(mu[x], 1ll * (a / x) * (b / x) * (c / x) % mod));
                        
    for (ri L = 1; L <= c; L ++) if(mu[L]) {
        int v = fac[L].size();
        for (ri S = 0; S <= (1 << v) - 1; S ++) {
            int x = 1; 
            rep(i, 0, v - 1) if(S & (1 << i)) x *= fac[L][i];
            if(x > b) continue;
            for (ri T = S & (S - 1); ; T = (T - 1) & S) {
                int D = 1;
                rep(j, 0, v - 1) if(T & (1 << j)) D *= fac[L][j];
                int y = 1ll * L * D / x;
                if(x > y && y <= a) {
                    d[x] ++; d[y] ++; 
                    eu[++ id] = x; ev[id] = y; ew[id] = L;
                    inc(ans, mul(mu[y], 1ll * (a / L) * (b / L) * (c / x) % mod));
                    inc(ans, mul(mu[y], 1ll * (a / x) * (b / L) * (c / L) % mod));
                    inc(ans, mul(mu[y], 1ll * (a / L) * (b / x) * (c / L) % mod));
                    inc(ans, mul(mu[x], 1ll * (a / L) * (b / L) * (c / y) % mod));
                    inc(ans, mul(mu[x], 1ll * (a / y) * (b / L) * (c / L) % mod));
                    inc(ans, mul(mu[x], 1ll * (a / L) * (b / y) * (c / L) % mod));
                }
                if(!T) break;
            }
        }
    }
            
    for (ri i = 1; i <= id; i ++) {
        int u = eu[i], v = ev[i];
        if(d[u] > d[v]) swap(u, v); 
        go[u].push_back(mp(v, ew[i]));
    }
            
    for (ri x = 1; x <= b; x ++) {
        for (auto Y : go[x]) vis[Y.first] = x, vv[Y.first] = Y.second;
        for (auto Y : go[x]) for (auto Z : go[Y.first]) if(vis[Z.first] == x) {
            static int res = 0, cer = 0;
            int y = Y.first, z = Z.first, xy = Y.second, yz = Z.second, xz = vv[z];
            res = 0; cer = mul(mu[x], mul(mu[y], mu[z]));
            inc(res, 1ll * (a / xy) * ((b / xz) * (c / yz) + (b / yz) * (c / xz)) % mod);
            inc(res, 1ll * (b / xy) * ((a / xz) * (c / yz) + (a / yz) * (c / xz)) % mod);
            inc(res, 1ll * (c / xy) * ((a / xz) * (b / yz) + (a / yz) * (b / xz)) % mod);
            inc(ans, mul(cer, res));
        }
    }   
        
    cout << ans << endl;
}

int main() {
    cin >> a >> b >> c;
    Init(); calc();
    return 0;
}
相關文章
相關標籤/搜索