codeforces803F 2100分容斥原理 + 莫比乌斯函数
发布日期:2021-05-06 15:23:12 浏览次数:13 分类:技术文章

本文共 1460 字,大约阅读时间需要 4 分钟。

题意:

给你 \dpi{150}n 个数的序列 \dpi{150}a ,问你 gcd = 1 的子序列方案数。

数据范围: 1 \leqslant n \;,\; a_i \leqslant 10^5 。

题解:

ans = cal(num[1]) - \sum cal(num[p]) + \sum cal(num[k])

p 的质因子个数是奇数个,且没有相同的质因子。

\dpi{150} k 的质因子个数是偶数个,且没有相同的质因子。

num[i] 表示序列中 i 的倍数的个数。

cal(x) 表示 x 个数形成的非空集合的个数。

这就是莫比乌斯函数。

感受:

关键是分析本质不同的质因子。

代码:

#include
using namespace std;typedef long long ll ;const int maxn = 1e5 + 5 ;const ll mod = 1e9 + 7 ;int n , cnt[maxn] , num[maxn] ;bool vis[maxn] ;int prime[maxn] ;int mu[maxn] ;void get_mu(){ int up = 1e5 ; int cnt = 0 ; mu[1] = 1 ; for(int i = 2 ; i <= up ; i ++) { if(!vis[i]) prime[++ cnt] = i , mu[i] = -1 ; for(int j = 1 ; j <= cnt && prime[j] * i <= up ; j ++) { vis[prime[j] * i] = 1 ; if(i % prime[j] == 0) break ; else mu[i * prime[j]] = -mu[i] ; } }}void init(){ int up = 1e5 ; num[1] = n ; for(int i = 2 ; i <= up ; i ++) for(int j = i ; j <= up ; j += i) num[i] += cnt[j] ;}ll qpow(ll a , ll b){ ll ans = 1 ; a %= mod ; while(b) { if(b & 1) ans = (ans * a) % mod ; b >>= 1 , a = (a * a) % mod ; } return ans % mod ;}ll cal(int x){ ll ans = 0 ; ans = qpow(2ll , ll(x)) ; ans = (ans - 1 + mod) % mod ; return ans ;}void solve(){ int up = 1e5 ; ll ans = cal(num[1]) ; for(int i = 2 ; i <= 1e5 ; i ++) { ans += ll(mu[i]) * cal(num[i]) ; ans %= mod ; } ans = (ans + mod) % mod ; printf("%lld\n" , ans) ;}int main(){ scanf("%d" , &n) ; memset(cnt , 0 , sizeof(cnt)) ; memset(num , 0 , sizeof(num)) ; for(int i = 1 ; i <= n ; i ++) { int x ; scanf("%d" , &x) ; cnt[x] ++ ; } get_mu() ; init() ; solve() ; return 0 ;}

 

上一篇:codeforces401D 2000分状压dp + 去重
下一篇:P4127 数位dp + 枚举模数

发表评论

最新留言

留言是一种美德,欢迎回访!
[***.207.175.100]2025年03月24日 17时39分24秒