• [CF585E] Present for Vitalik the Philatelist


    [题目链接]

    https://codeforces.com/contest/585/problem/E

    [题解]

    (s_{n}) 表示最大公约数恰好为 (n) 的集合个数 , (f_{n}) 表示与 (n) 互质的数个数。

    那么答案为 (sum{s_{i}f_{i}})

    考虑计算 (f) , 令 (c_{i}) 表示 (i) 的出现次数。

    那么有 (f_{n} = sum_{i}{[gcd(i , n) = 1]c_{i}} = sum_{i}{c_{i}}sum_{d|i,d|n}{mu(d)} = sum_{d|n}{mu(d)}sum_{d|i}{c_{i}})

    不妨令 (g_{k} = sum_{k|i}{c_{i}} , g'_{k} = mu(k)g(k)) , 那么 (f_{n} = sum_{d|n}{g'_{d}})

    再考虑求 (s_{i}) , 不妨令 (s'_{i}) 为最大公约数为 (i) 倍数的方案数 , 显然 (s'_{i} = 2 ^ {g_{i}} - 1)

    又有 (s'_{i} = sum_{i|d}{s_{d}})

    这两个式子都是 (a_{k} = sum_{d|k}{b_{k}})(a_{k} = sum_{k|d}{b_{k}}) 的形式 , 可以求狄利克雷前缀和 (第二个式子实质上是求逆)。

    时间复杂度 : (O(NlogN))

    [代码]

    #include<bits/stdc++.h>
    
    using namespace std;
    
    #define rep(i , l , r) for (int i = (l); i < (r); ++i)
    
    typedef long long LL;
    
    const int MN = 5e5 + 5 , MM = 1e7 + 5 , mod = 1e9 + 7;
    
    int n , lim , s[MM] , two[MN] , a[MN] , tot[MM] , g[MM] , pr[MM / 10] , cnt , mu[MM] , vis[MM];
    
    inline void inc(int &x , int y) {
    	 x = x + y < mod ? x + y : x + y - mod;
    }
    inline void dec(int &x , int y) {
    	 x = x - y >= 0 ? x - y : x - y + mod;
    }
    inline void prework(int n) {
    	 mu[1] = 1;
    	 for (int i = 2; i <= n; ++i) {
    	 		if (!vis[i]) pr[++cnt] = i , mu[i] = -1;
    	 		for (int j = 1; j <= cnt && i * pr[j] <= n; ++j) {
    	 				vis[i * pr[j]] = 1;
    					if (i % pr[j] == 0) {
    							mu[i * pr[j]] = 0;
    							break;
    					}	else mu[i * pr[j]] = -mu[i];
    			}  
    	 }
    }
    int main() {
    		
    		scanf("%d" , &n); two[0] = 1;
    		for (int i = 1; i <= 500000; ++i) two[i] = 2ll * two[i - 1] % mod;
    		for (int i = 1; i <= n; ++i) {
    				scanf("%d" , &a[i]);
    				++tot[a[i]];
    		}
    		lim = *max_element(a + 1 , a + 1 + n); prework(lim);
    		for (int i = 1; i <= cnt; ++i)
    		for (int j = lim / pr[i]; j; --j)
    				tot[j] += tot[j * pr[i]];
    		for (int i = 1; i <= lim; ++i) g[i] = (1ll * tot[i] * mu[i] % mod + mod) % mod;
    		for (int i = 1; i <= cnt; ++i)
    		for (int j = 1; j * pr[i] <= lim; ++j)
    				inc(g[j * pr[i]] , g[j]);
    		for (int i = 1; i <= lim; ++i) s[i] = two[tot[i]] - 1;
    		for (int i = cnt; i; --i)
    		for (int j = 1; j * pr[i] <= lim; ++j)
    				dec(s[j] , s[j * pr[i]]);
    		int ans = 0;
    		for (int i = lim; i > 1; --i) inc(ans , 1ll * s[i] * g[i] % mod);
    		printf("%d
    " , ans);
    	  return 0;
    }
  • 相关阅读:
    idea--不能启动问题
    linux--mysql5.7安装
    vmware
    debezium
    java枚举
    springfox
    日志级别
    lombok--知识点
    es6--箭头函数
    网址访问过慢
  • 原文地址:https://www.cnblogs.com/evenbao/p/14321389.html
Copyright © 2020-2023  润新知