1.公式:(总共有
项) -
(总共有
项) +
(总共有
项)然后再减四项的,再加五项的,以此类推。
2.从公式可以看出总共有,如果再在左侧加一个
是不是总共就有
项,为什么能,从上述公式可以看出,从n个中选0个,选一个,选两个,一直到n个,是不是就是从n个集合中选任意多个集合的意思,有选或者不选两种可能,总共n给数所以是
(上述公式我们补了一个
,所以减一)。
证明:
不妨假设x,在k个集合中;
那么我们来求k被加了多少次,观察式子可知k被加了
,如图:
例题:
1活动 - AcWing(能被整除的数)
1.分析题目为什么是使用容斥定理,题目需要我们求1~n的范围内,能被p1,p2,...pm中至少一个整除的数总共有多少个,如果我们不是用容斥定理,我们就要算出每一个质数,能整除的数有那些,算出来之后,很明显,有一些数及能被这个数整除又能被那个数整除,所以这样算是非常麻烦的,所以我们需要用到容斥定理,
2.公式如下
表示第i个质素能整除1~n中数的个数,那
怎么求能,求一个数能整除1~n中多少个数,就是
,有交集的又怎么求呢?有交集的就是他们的最小公倍数除以n(应为他们都是素数,他们的最小公倍数就是他们的乘积)。
下面是代码:
#include<iostream>
using namespace std;
typedef long long ll;
const int N = 20;
ll n,m;
ll p[N];
ll res;
int main()
{
cin>>n>>m;
for(int i = 0;i < m;i ++)cin>>p[i];
for(int i = 1;i < 1<<m;i ++)//由上述容斥定理公式可知,有二的n次幂减一项,这样枚举就想当面深搜暴力所有情况。
{
ll t = 1,cnt = 0;//t记录某个情况下那些奇数的积,cnt记录用了多少给集合。
for(int j = 0;j < m;j ++)
if(i>>j&1)
{
cnt++;
if((ll)p[j]*t > n)//如果超过了n,那就没必要再求了(超范围了)。
{
t = -1;//记录一下这个情况
break;
}
t *= p[j];
}
if(t!=-1)
{
if(cnt%2)res+=n/t;//如果是奇数个集合加,偶数个集合就是减(由公式可知)。
else res -=n/t;
}
}
cout<<res<<endl;
}