话说直接这样从百度上摘下来,真滴好嘛QAQ
在计数时,必须注意没有重复,没有遗漏。为了使重叠部分不被重复计算,人们研究出一种新的计数方法,这种方法的基本思想是:先不考虑重叠的情况,把包含于某内容中的所有对象的数目先计算出来,然后再把计数时重复计算的数目排斥出去,使得计算的结果既无遗漏又无重复,这种计数的方法称为容斥原理。
虽然我也不想一大段一大段的让泥萌看,但是真滴有用qwq
也可表示为 设S为有限集, ,则 两个集合的容斥关系公式:A∪B =|A∪B| = |A|+|B| - |A∩B |(∩:重合的部分) 三个集合的容斥关系公式:|A∪B∪C| = |A|+|B|+|C| - |A∩B| - |B∩C| - |C∩A| + |A∩B∩C| 详细推理如下: 1、 等式右边改造 = {[(A+B - A∩B)+C - B∩C] - C∩A }+ A∩B∩C 2、文氏图分块标记如右图图:1245构成A,2356构成B,4567构成C 3、等式右边()里指的是下图的1+2+3+4+5+6六部分: 那么A∪B∪C还缺部分7。 4、等式右边[]号里+C(4+5+6+7)后,相当于A∪B∪C多加了4+5+6三部分, 减去B∩C(即5+6两部分)后,还多加了部分4。 5、等式右边{}里减去C∩A (即4+5两部分)后,A∪B∪C又多减了部分5, 则加上A∩B∩C(即5)刚好是A∪B∪C。
对于上面的公式,简单理解呢就是,对于它们相交的部分,如果是奇数个相交就加起来,偶数个就减去
对于容斥的理解差不多了,主要还是给泥萌看一道例题
题目描述:
V_Dragon有n盏电灯泡,编号为1-n,每个灯泡都有一个开关,那么问题来了
1.所有灯泡初始时为不亮的;
2.V_Dragon分别进行三次操作;
3.每次操作他都选一个质数x,将编号为x和x的整数倍的灯泡的开关都拨动一下(如果灯为亮,那么拨动以后灯为不亮,如果灯不亮,拨动以后变为亮)
求最后亮着的灯的数量;
输入:
输入T表示T组测试数据(1<=T<=100)
接下来T组数据
每组第一行一个n表示灯泡各数(1<=n<=10^9)
第二行三个数a,b,c表示V_Dragon每次选择的数(1<=a,b,c<=10^6)(a,b,c全为质数且a,b,c两两互不相等)
输出:
最后亮着的灯的个数
样例输入:
1
30
2 3 5
样例输出:
15
#include<cstdio>
int main()
{
int T,n,a,b,c;
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
scanf("%d%d%d",&a,&b,&c);
int sum=n/a+n/b+n/c-2*(n/a/b+n/b/c+n/a/c)+4*(n/a/b/c);
//long long int sum= n/a+n/b+n/c-2*( n/(a*b) + n/(b*c) + n/(a*c) )+4*( n/(a*b*c) )
//这里 其实应该是n*gcd(a,b)/(a*b)...但是因为题目中说a,b,c互质,所以gcd=1,但是如果题目中不说互质,就需要乘以gcd
printf("%d",sum);
}
return 0;
}
还有一道简单容斥例题https://www.51nod.com/onlineJudge/questionCode.html#!problemId=1284
求2,3,5,7的倍数
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;
int main()
{
__int64 n,sum;
scanf("%I64d",&n);
sum=n;
sum-=(n/2+n/3+n/5+n/7);
sum+=(n/6+n/10+n/14+n/15+n/21+n/35);
sum-=(n/30+n/42+n/70+n/105);
sum+=(n/210);
printf("%I64d",sum);
return 0;
}