09容斥原理

容斥原理

定理: 共有n个集合,它们的并可以表示为如下关系
∣ A 1 ∪ A 2 ∪ . . . ∪ A n ∣ = ∑ i = 1 n ( − 1 ) i − 1 ∑ i 个 数 的 组 合 ∣ A p 1 ∩ A p 2 ∩ . . . ∩ A p i ∣ |A_{1} \cup A_{2} \cup...\cup A_{n}| = \sum_{i=1}^n{(-1)^{i-1}\sum_{i个数的组合}{|A_{p_{1}} \cap A_{p_{2}} \cap...\cap A_{p_{i}}|}} A1A2...An=i=1n(1)i1iAp1Ap2...Api

证明:
goal:对任意一个元素,它在左式和右式都只被计算了一次
设某个元素被k个集合包含,显然地,其对左式的贡献为1,因为在并集中只计算一次。
接下来证明它在右式被计算的次数也为1

  1. i = 1时被计算了k次
  2. i = 2时被计算了 C k i C_{k}^{i} Cki 当然,此时为负数

依次类推,可得到计算次数为 ∑ i = 1 k C k i ( − 1 ) i + 1 = − ∑ i = 1 k C k i ( − 1 ) i \sum_{i=1}^{k}{C_{k}^i(-1)^{i+1}} = -\sum_{i=1}^{k}{C_{k}^i(-1)^{i}} i=1kCki(1)i+1=i=1kCki(1)i,这是 − ( 1 − x ) k + C k 0 -(1-x)^k+C_{k}^{0} (1x)k+Ck0 x = 1 x=1 x=1之后的展开式,显然结果为1。
再由k的任意性,可以得到结论,证毕

原题链接:能被整除的数

给定一个整数 n 和 m 个不同的质数 p1,p2,…,pm。
请你求出 1∼n 中能被 p1,p2,…,pm 中的至少一个数整除的整数有多少个。

#include <iostream>

using namespace std;

/*
 思路:至少被一个整除,相当于求整除的并,此时就就可以使用容斥原理了 
 1. s_{i} - s_{i, j} + s_{i, j, k} -...+... (其中s_{i, j}表示n中同时被pi和pj整除的数)
 2. 枚举出每个子集,计算s,并判断加减,奇数加,偶数减 
 Tip:1~n中能被pi整除的数的个数就是 n / pi(这是下取整的)因为pi与pj都是不同的质数,n / (pi * pj)就是s_{i, j}的结果 
*/ 


const int N = 20;

int n, m;
int p[N]; 

// 计算x所代表的集合的元素个数 
int cal(int x, int dis) {
	int res = n, flag = 0;
	for (int i = 0; i < dis; i ++ ) {
		if (x >> i & 1) {
			flag ++ ;
			res /= p[i];
		}
	}
	//cout << res << endl;
	return flag % 2 == 0 ? -res : res;
}

int main() {
	cin >> n >> m;
	for (int i = 0; i < m; i ++ ) cin >> p[i];
	int res = 0;
	// 枚举所有子集,每个pi只有选和不选两种情况 
	for (int i = 1; i < (1 << m); i ++ ) {
		res += cal(i, m);
	}
	cout << res << endl;
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值