容斥原理

容斥原理:

假如又4个集合,分别为A, B, C,求这三个集合的并集:

S(a) :表示A集合中元素的个数

S = S(a) +  S(b) +  S(c)(项的个数是奇数)

      - S(a 交 b)- S(a 交 c) - S(b 交 c)(偶数)

   + S(a 交 b 交 c)(奇数)

故可知奇数加偶数减

N个集合的并集的项个数  =  2^N-1 , 所以可以用N个二进制位表示每个项 , 也就是从0 到 1 << N - 1 进行遍历

看题:

给定一个整数nn和mm个不同的质数p1,p2,,pmp1,p2,…,pm。

请你求出11~nn中能被p1,p2,,pmp1,p2,…,pm中的至少一个数整除的整数有多少个。

输入格式

第一行包含整数nn和mm。

第二行包含mm个质数。

输出格式

输出一个整数,表示满足条件的整数的个数。

数据范围

1m161≤m≤16,
1n,pi1091≤n,pi≤109

输入样例:

10 2
2 3

输出样例:

7


 1 #include <iostream>
 2 using namespace std;
 3 
 4 typedef long long ll;
 5 
 6 ll p[20];
 7 
 8 int main(){
 9     int n, m;cin >> n >> m;
10     for(int i = 0;i < m;++i) cin >> p[i];
11     ll ans = 0;
12     //枚举所有的集合选取情况 2^m - 1种
13     for(int i = 1;i < 1 << m;++i){
14         ll mul = 1;//用来存当前项所有质数的乘积
15         ll cnt = 0;//质数个数
16         for(int j = 0;j < m;++j)
17             if(i >> j & 1){
18                 if(mul * p[j] > n){
19                     mul = -1;
20                     break;
21                 }
22                 mul *= p[j];
23                 ++cnt;
24             }
25         if(mul != -1){
26             //奇数加偶数减,ans统计当前这个组合从1到n有多少个数整除p
27             if(cnt % 2) ans += n / mul;//n除一个质数就等于从1到n有多少个数是这个质数的倍数
28             else ans -= n / mul;
29         }
30     }
31     cout << ans << endl;
32     return 0;
33 }
View Code
原文地址:https://www.cnblogs.com/sxq-study/p/12285144.html