codeforces 1436 F - Sum Over Subsets (莫比乌斯反演)

题目链接:https://codeforces.com/contest/1436/problem/F

题目大意:

一个多重集 \(S\),有 \(m\) 种不同的数,第 \(i\) 种数为 \(a_i\),有 \(freq_i\) 个。

求满足如下条件的和式 \(∑x∈A∑y∈Bxy∑x∈A∑y∈Bxy\) 的值:

\[B⊂A \]

\[|B|=|A|−1|B|=|A|−1 \]

\[gcdx∈A{x}=1 \]

注意,其中 \(A,B\) 也为多重集。

涉及 \(gcd\) 的式子一般可以用套路莫比乌斯反演

\(f(i)\)\(gcd\)\(i\) 时的答案
很难直接算
于是另 \(g(i) = sum_{i \mid d} \mu(\frac{d}{i})f(d)\)

答案就是 $$f(1) = sum_{i = 1}^n \mu(i)g(i)$$

考虑计算 \(g(i)\), 将所有 \(i\) 的倍数找出来放到一个集合中,计算这个集合的答案
设该集合大小为 \(k\), 考虑每一对 \(a_i * a_j\) 的贡献,

当x和y是同一个数的时候,贡献是 \(x^2(k−1)2^{k-2}freq[x]\)

当x和y数值相同但不是同一个数的时候,贡献是 \(x^2[(k−2)2^{k-3}+2^{k−2}]freq[x](freq[x]−1)\)

当x不等于y的时候,贡献是 \(xy[(k−2)2^{k-3}+2^{k−2}]freq[x]freq[y]\)

(上述公式是考虑 \(B\) 是由 \(A\) 删去了哪个数得出的)

\(x, y\) 不相等的情况还是无法直接枚举,发现 \(y\) 一定是 \(i\) 的倍数,所以推一下式子用前缀和优化一下即可

注意: 取模一定要仔细

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> P;

const int maxn = 100010;
const ll M = 998244353;
const int N = 100000;

int n, m;
ll ans;
ll a[maxn], c[maxn];
int is[maxn], prime[maxn], mu[maxn], cnt = 0;

ll qsm(ll i, ll po){
	ll res = 1;
	while(po){
		if(po & 1) res = 1ll * res * i % M;
		po >>= 1;
		i = 1ll * i * i % M;
	}
	return res;
}

vector<P> v;

ll read(){ ll s = 0, f = 1; char ch = getchar(); while(ch < '0' || ch > '9'){ if(ch == '-') f = -1; ch = getchar(); } while(ch >= '0' && ch <= '9'){ s = s * 10 + ch - '0'; ch = getchar(); } return s * f; }

int main(){
	ll inv = qsm(2, M - 2);
	
	m = read();
	for(int i = 1 ; i <= m ; ++i) {
		a[i] = read(), c[a[i]] = read();
	}
	
	mu[1] = 1, is[1] = 1;
	for(int i = 2 ; i <= N ; ++i){
		if(!is[i]){
			prime[++cnt] = i;
			mu[i] = -1;
		}
		for(int j = 1 ; j <= cnt && i * prime[j] <= N ; ++j){
			is[i * prime[j]] = 1;
			if(i % prime[j] == 0){
				mu[i * prime[j]] = 0;
				break;
			} else{
				mu[i * prime[j]] = -mu[i];
			}
		}
	}
	
	for(int i = 1 ; i <= N ; ++i){
		v.clear();
		ll s1 = 0, s2 = 0, s3 = 0, s = 0;
		ll K = 0; 
		
		for(int j = i ; j <= N ; j += i){ // 统计集合大小 
			if(!c[j]) continue;
			K += c[j];
			s = (s + 1ll * j * c[j] % M) % M;
			v.emplace_back(j, c[j]);
		}
		
		for(auto j : v){
			ll tt = 0;
			if(K >= 2){
				tt = qsm(2, K - 2);
				s1 = (s1 + 1ll * j.first * j.first % M * ((K - 1) % M) % M * tt % M * j.second % M) % M;
			}
			if(K >= 3){
				tt = (tt + 1LL * (K - 2) % M * tt % M * inv % M) % M;
			}
		    s2 = (s2 + 1LL * j.first * j.first % M * tt % M * j.second % M * (j.second - 1) % M) % M;
            s3 = (s3 + 1LL * j.first * j.second % M * tt % M * (s - 1LL * j.first * j.second % M) % M) % M;
		}
		
		ans = ((ans + 1ll * mu[i] * ((s1 + s2 + s3) % M)) % M + M) % M;
	}
	
	printf("%lld\n", ans);
	
	return 0;
}
posted @ 2021-01-16 12:37  Tartarus_li  阅读(170)  评论(0编辑  收藏  举报