一、容斥原理
在计数时,要保证无一重复,无一遗漏。为了使重叠部分不被重复计算,在不考虑重叠的情况下,把包含于某内容中的所有对象的数目先计算出来,然后再把计数时重复计算的数目排斥出去,使得计算的结果既无遗漏又无重复,这种计数的方法称为容斥原理。
1.容斥原理1——两个集合的容斥原理
如果被计数的事物有A、B两类,那么,先把A、B两个集合的元素个数相加,发现既是A类又是B类的部分重复计算了一次,所以要减去。如图所示:
公式:A∪B=A+B-A∩B
总数=两个圆内的-重合部分的
2.容斥原理2——三个集合的容斥原理
如果被计数的事物有A、B、C三类,那么,将A、B、C三个集合的元素个数相加后发现两两重叠的部分重复计算了1次,三个集合公共部分被重复计算了2次。
如图所示,灰色部分A∩B-A∩B∩C、B∩C-A∩B∩C、C∩A-A∩B∩C都被重复计算了1次,黑色部分A∩B∩C被重复计算了2次,因此总数A∪B∪C=A+B+C-(A∩B-A∩B∩C)-(B∩C-A∩B∩C)-(C∩A-A∩B∩C)-2A∩B∩C=A+B+C-A∩B-B∩C-C∩A+A∩B∩C。即得到:
公式:A∪B∪C=A+B+C-A∩B-B∩C-C∩A+A∩B∩C
总数=三个圆内的-重合两次的+重合三次的
上面只是简单介绍一下容斥原理,那么代码如何写呢
就可以看看一篇讲的比较好的博客,里面有具体的实现方法还包括欧拉函数和抽屉原理的讲解。
点击打开博客http://blog.csdn.net/qq_36368339/article/details/70217849
附上两个实际的例子:
题目链接:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1284
我只是单纯的应用到了这个原理,代码写得有点直接。
正确代码:
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
typedef long long LL;
const LL maxn=1e18;
int main()
{
LL n;
while(~scanf("%lld",&n))
{
LL a,b,c,d,ab,ac,ad,bc,bd,cd,abc,acd,abd,bcd,abcd;//15
a=n/2;
b=n/3;
c=n/5;
d=n/7;
ab=n/6;
ac=n/10;
ad=n/14;
bc=n/15;
bd=n/21;
cd=n/35;
abc=n/30;
acd=n/70;
abd=n/42;
bcd=n/105;
abcd=n/210;
abc=abc-abcd;//仅包括同时能被2,3,5整除的数,下面得到的结果依次类推
abd=abd-abcd;
acd=acd-abcd;
bcd=bcd-abcd;
ab=ab-(abc+abd+abcd);
ac=ac-(abc+acd+abcd);
ad=ad-(abd+acd+abcd);
bc=bc-(abc+bcd+abcd);
bd=bd-(abd+bcd+abcd);
cd=cd-(acd+bcd+abcd);
a=a-(ab+ac+ad+abc+abd+acd+abcd);
b=b-(ab+bc+bd+abc+abd+bcd+abcd);
c=c-(ac+bc+cd+abc+acd+bcd+abcd);
d=d-(ad+bd+cd+abd+acd+bcd+abcd);
LL ans;
ans=n-(a+b+c+d+ab+ac+ad+bc+bd+cd+abc+abd+acd+bcd+abcd);//此时的各部分之间没有重叠
printf("%lld\n",ans);
}
return 0;
}
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6106
容斥原理
正确代码:
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
int n,maxn=-1;
scanf("%d",&n);
for(int i=0;i<n;i++)
{
int a,b,c,d,e,f,g,ab,bc,ac,abc;
scanf("%d%d%d%d%d%d%d",&a,&b,&c,&d,&e,&f,&g);
//接下来的操作将各部分之间重复的排除
d-=g;//ab
e-=g;//bc
f-=g;//ac
a=a-(d+f+g);
b=b-(d+e+g);
c=c-(e+f+g);
if(a<0||b<0||c<0||d<0||e<0||f<0||g<0)//判断数据是否有误
continue;
int s=a+b+c+d+e+f+g;
if(s>maxn)
maxn=s;
}
printf("%d\n",maxn);
}
return 0;
}