集合中的质数(容斥原理)

集合中的质数
在这里插入图片描述
就是求 ∣ A 1 ∪ A 2 ∪ A 3 . . . ∪ A n ∣ , 其 中 A i 表 示 a i 的 倍 数 的 个 数 。 |A_1 \cup A_2 \cup A_3...\cup A_n|,其中A_i表示a_i的倍数的个数。 A1A2A3...An,Aiai
在这里插入图片描述

如 图 ∣ A ∪ B ∪ C ∣ = ∣ A ∣ + ∣ B ∣ + ∣ C ∣ − ∣ A ∩ B ∣ − ∣ A ∩ C ∣ − ∣ B ∩ C ∣ + ∣ A ∩ B ∩ C ∣ , 这 是 最 基 础 的 容 斥 , 可 以 推 广 到 n 个 集 合 的 容 斥 : 如图|A \cup B \cup C|=|A|+|B|+|C|-|A \cap B|-|A \cap C|-|B\cap C|+|A\cap B\cap C|,这是最基础的容斥,可以推广到n个集合的容斥: ABC=A+B+CABACBC+ABC,广n
∣ A 1 ∪ A 2 ∪ A 3 . . . ∪ A n ∣ = ∑ ∣ A i ∣ − ∑ ∣ A i ∩ A j ∣ + ∑ ∣ A i ∩ A j ∩ A k ∣ − . . . + ( − 1 ) n − 1 ∑ ∣ A 1 ∩ A 2 ∩ . . . . ∩ A n ∣ |A_1 \cup A_2 \cup A_3...\cup A_n|=\sum|A_i|-\sum|A_i \cap A_j|+\sum|A_i \cap A_j \cap A_k|-...+(-1)^{n-1}\sum|A_1 \cap A_2 \cap....\cap A_n| A1A2A3...An=AiAiAj+AiAjAk...+(1)n1A1A2....An 可 以 看 出 奇 加 偶 减 , 设 f ( a i , a j . . . a k ) 为 1 − m 中 , a i , a j . . . a k 的 倍 数 的 个 数 , 则 f ( a i ) = m a i , f ( a i , a j . . . a k ) = m l c m ( a i , a j . . . a k ) , 本 题 a i 是 质 数 , 所 以 l c m 就 是 ∏ a i 可以看出奇加偶减,设f(a_i,a_j...a_k)为1-m中,a_i,a_j...a_k的倍数的个数,则f(a_i)=\frac{m}{a_i},f(a_i,a_j...a_k)=\frac{m}{lcm(a_i,a_j...a_k)},本题a_i是质数,所以lcm就是 \prod a_i ,f(ai,aj...ak)1mai,aj...ak,f(ai)=aim,f(ai,aj...ak)=lcm(ai,aj...ak)m,ailcmai
这里用的二进制枚举,设一个n位二进制数,第i位取0,1分别表示不是 a i a_i ai倍数和是 a i a_i ai倍数,那么一共有 2 n − 1 2^n-1 2n1(至少是一个数的倍数)种状态,遍历一遍就好了。

#include <iostream>
#include <cstring>
#include <cmath>
#include <bitset>
#include <queue>
#include <vector>
#include <cstdio>
#include <set>
#include <stack>
#include <sstream>
#include <cstring>
#include <algorithm>
#include <map>
#define rep(i, a, b) for (long long i= a; i <= b; i++)
#define reps(i, a, b) for (long long i = a; i >= b; i--)
#define gcd(a,b) __gcd(a,b)
#define lcm(a,b) a*b/gcd(a,b)
#define ls(node) tree[node].ls
#define rs(node) tree[node].rs
#define val(node) tree[node].val
#define sum(node) tree[node].sum
#define lazy(node) tree[node].lazy
#define lazy1(node) tree[node].lazy1
#define lazy2(node) tree[node].lazy2
#define tr(node) tree[node]
using namespace std;
const int N=1e6+7;
const int inf=0x3f3f3f3f;
const int mod=1e9+7;
typedef long long ll;
#define Rep(i,a,b)for(ll i=a;i<=b;i++)
int a[N];
ll solve(int n,int m)
{
    ll ans=0;
    for(int i=1;i<(1<<n);i++){//枚举每一种情况
        ll cnt=0,lcm=1;
        for(int j=0;j<n;j++){
            if(1<<j&i){//判断第j位是不是1
                cnt++;
                lcm*=a[j+1];//因为我的数组从1开始的所以是j+1
            }
        }
        if(cnt&1)ans+=m/lcm;//奇加偶减
        else ans-=m/lcm;
    }
    return ans;
}
int main()
{
    ll n,m;
    scanf("%lld%lld",&n,&m);
    rep(i,1,n)scanf("%d",&a[i]);
    printf("%lld\n",solve(n,m));
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值