zoukankan      html  css  js  c++  java
  • loj#6076「2017 山东一轮集训 Day6」三元组 莫比乌斯反演 + 三元环计数

    题目大意:

    给定(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 $


    首先莫比乌斯反演

    $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] $

    (= 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))

    (= 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)})

    那么考虑计算这个式子

    注意到其实有效的三元组((x, y, z))是十分稀少的

    我们考虑用一种高效的办法来找到所有的三元组

    三元环计数是一个十分便利的算法

    如果(mu(u), mu(v) eq 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;
    }
    
  • 相关阅读:
    QA的几个经典问题(1)
    QA的几个经典问题(2)
    通过Android录音进行简单音频分析
    Android在TextView中实现RichText风格
    Handler Should be static or leaks Occur?
    如何查看华为EMUI系统APK源码?
    ServiceManager: Permmission failure: android.permission.RECORD_AUDIO
    Android 4.4以上的存储读写权限
    如何使用Android中hide的类和方法进行开发?
    在Mac mini上编译Android源码
  • 原文地址:https://www.cnblogs.com/reverymoon/p/10279706.html
Copyright © 2011-2022 走看看