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;
}