数学之容斥原理

容斥原理

P890 能被整除的数

容斥原理:
A ∪ B ∪ C ⋅ ⋅ H ∪ I ⋅ ⋅ ⋅ = A + B + C + ⋅ ⋅ ⋅ ⋅ ⋅ − ( A ∩ B ) − ( A ∩ C ) − ⋅ ⋅ ⋅ ⋅ + ( A ∩ B ∩ C ) + ( B ∩ C ∩ D ) − ( A ∩ B ∩ C ∩ D ) − ( A ∩ C ∩ D ∩ E ) ⋅ ⋅ ⋅ ⋅ ⋅ A\cup B \cup C··H\cup I···=A+B+C+·····-(A\cap B)-(A \cap C)-····+(A\cap B\cap C)+(B\cap C\cap D)-(A\cap B\cap C\cap D)-(A\cap C\cap D\cap E)····· ABCHI=A+B+C+(AB)(AC)+(ABC)+(BCD)(ABCD)(ACDE)
时间复杂度分析:一个集合共有 C n 1 C_n^1 Cn1项,两个集合共有 C n 2 C_n^2 Cn2项,以此类推,所以最后共有 C n 1 + C n 2 + ⋅ ⋅ ⋅ ⋅ + C n n C_n^1+C_n^2+····+C_n^n Cn1+Cn2++Cnn项,把这个式子补加一个 C n 0 C_n^0 Cn0答案为 2 n 2^n 2n,所以这个式子最后有 2 n − 1 2^n-1 2n1项,时间复杂度为O( 2 n 2^n 2n-1)

证明:
思路:只需证明等式左边的每一个元素在右边都恰好被加了一次
设左边任意元素x,在k个集合中出现过,设T为x被加的次数,
则T= C k 1 − C k 2 + C k 3 − C k 4 + ⋅ ⋅ ⋅ ⋅ + ( − 1 ) k − 1 ⋅ C k k C_k^1-C_k^2+C_k^3-C_k^4+····+(-1)^{k-1}\cdot C_k^k Ck1Ck2+Ck3Ck4++(1)k1Ckk
通过二项式定理得 ( 1 − x ) k = C k 0 − C k 1 ⋅ x 1 + C k 2 ⋅ x 2 − C k 3 ⋅ x 3 + ⋅ ⋅ ⋅ ( − 1 ) k ⋅ C k k ⋅ x k (1-x)^k=C_k^0-C_k^1\cdot x^1+C_k^2\cdot x^2-C_k^3\cdot x^3+···(-1)^k\cdot C_k^k\cdot x^k (1x)k=Ck0Ck1x1+Ck2x2Ck3x3+(1)kCkkxk,当x为1时,原式等于 C k 0 − T = 1 − T = 0 C_k^0-T=1-T=0 Ck0T=1T=0,所以T=1,QED.

暴力:O(nm)会超时,只能用容斥原理
时间复杂度分析: 1~n中p的倍数的个数为 ⌊ n p ⌋ \lfloor\frac{n}{p}\rfloor pn ,集合 S i S_i Si表示1~n中pi的倍数,假设算集合 S 1 ∩ S 2 ⋅ ⋅ ⋅ ∩ S m S_1\cap S_2···\cap S_m S1S2Sm中的元素个数时,我们需要计算 n p 1 ⋅ p 2 ⋅ ⋅ ⋅ p m \frac{n}{p_1\cdot p_2···p_m} p1p2pmn,需要计算m次,时间复杂度为O(m),我们共有 2 m − 1 2^m-1 2m1个集合,所以总时间复杂度O( 2 m ∗ m 2^m*m 2mm)
本题也用到二进制枚举状态

#include<iostream>
#include<algorithm>
typedef long long LL;
using namespace std;
const int N=20;
int n,m;
int p[N];
int main(){
	scanf("%d%d",&n,&m);
	for(int i=0;i<m;i++) scanf("%d",&p[i]);
	int res=0;
	//一共有2^m-1项
	for(int i=1;i<1<<m;i++){ //用m位二进制来表示状态 
		int t=1;//质数乘积 
		int cnt=0; //每种选法中包含几个集合 
		for(int j=0;j<m;j++){ //分别看每一位 
			if(i>>j&1){
				if((LL)t*p[j]>n){
					t=-1;
					break;
				}
				t*=p[j];
				cnt++;
			}
		}
		if(t!=-1){
			if(cnt%2) res+=n/t; //选中的集合数为奇数时加 
			else res-=n/t; //偶数时减 
		}
	}
	printf("%d",res);
	return 0;
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值