zoukankan      html  css  js  c++  java
  • codeforces 1436 F

    题目链接: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
    ", ans);
    	
    	return 0;
    }
    
  • 相关阅读:
    双循环解决添加列表问题
    贪心算法
    隔板法发红包
    python小兵之时间模块
    开发规范
    python 小兵(12)模块1
    Linux系统
    刷题
    Socket
    栈和队列
  • 原文地址:https://www.cnblogs.com/tuchen/p/14285524.html
Copyright © 2011-2022 走看看