标签:容斥原理
一、知识梳理
(一)定义:
如果被计数的事物有A、B、C三类,那么,A类和B类和C类元素个数总和= A类元素个数+ B类元素个数+C类元素个数—既是A类又是B类的元素个数—既是A类又是C类的元素个数—既是B类又是C类的元素个数+既是A类又是B类而且是C类的元素个数。(A∪B∪C = A+B+C - A∩B - B∩C - C∩A + A∩B∩C) 。
(二)公式:
两个集合的容斥关系公式:A∪B =|A∪B| = |A|+|B| - |A∩B |(∩:重合的部分)
三个集合的容斥关系公式:|A∪B∪C| = |A|+|B|+|C| - |A∩B| - |B∩C| - |C∩A| + |A∩B∩C|。
(三)韦恩图:
(具体证明过程可以参见百度百科或者博客:https://blog.csdn.net/lxt_lucia/article/details/81066272)
二、实战训练
时间限制: 1 Sec 内存限制: 128 MB
题目描述
学佛Fife最喜欢Bemy上的数学课了。因为他可以在数学课上尽情的蒸发学水~
Bemy为了不让学佛Fife过度骄傲,以保证每一个学水都能不被他影响,自信地不断地进步,给Fife一个有挑战性的数学题。
因为Fife不想让妹子Maze等得太久,决定把这道题交给你。
题目是这样的:有一个表达式(B+E+S+S+I+E)(G+O+E+S)(M+O+O)
其中B,E,S,I,G,O,M为七个变量(注意“O”是变量不是0)。
对于每个变量,Bemy会告诉Fife这个变量所代表的各个可能值。
Bemy想问问Fife这样一个问题:原表达式有多少种可能的情况,使表达式的值为偶数。(只要有一个变量的值不同,即为一种情况)
输入
第一行输入包含一个整数N。
下一个N 行每行包含一个变量名称和一个这个变量可以使用的值。
注:每个变量在整张表中不会出现多于20 次。
同一个变量不存在两个相同的值。所有给出的值都在-300……300 之间。
输出
打印出一个整数,表示有多少种方法使表达式的值为一个偶数。
样例输入
10
B 2
E 5
S 7
I 10
O 16
M 19
B 3
G 1
I 9
M 2
样例输出 Copy
6
提示
样例解释
(B,E,S,I,G,O,M)=(2,5,7,10,1,16,19)->53,244
=(2,5,7,10,1,16,2)->35,496
=(2,5,7,9,1,16,2)->34,510
=(3,5,7,10,1,16,2)->36,482
=(3,5,7,9,1,16,19)->53,244
=(3,5,7,9,1,16,2)->35,496
【数据规模】
对于30%的数据,N<=60。
对于100%的数据,N<=140。
我们初中就已经学过了奇数和偶数的相关知识,不妨跟着笔者来回顾一下
设a为奇数,b为偶数;
a = xy,b=st(乘号省略)
很容易得出:x和y均为奇数;s和t中至少有一个是偶数。
那么回到题目
(B+E+S+S+I+E)(G+O+E+S)(M+O+O) ,不妨记这三部分为a,b,c,要使abc是偶数,那么三者中至少一个偶数。
然后再看每一部分,(B+E+S+S+I+E),2E和2S一定是偶数,相加也是偶数,所以2E和2S对这个式子的奇偶性不起决定性作用,所以只要看(B+I)即可,同理,c也可以化简为M。
综上:abc=(B+I)(G+O+E+S)M。
接下来应用容斥原理,先求出a、b、c所有的组合数,再求出a、b、c为偶数的情况,下面用语言描述一下公式
(稍微有点复杂,可能直接看代码容易理解)
abc为偶数=a为偶数xb种数xc种数+a种数xb为偶数xc种数+a种数xb种数xc为偶数-a为偶数xb为偶数xc种数-a为偶数xb种数xc为偶数-a种数xb为偶数xc为偶数+a为偶数xb为偶数xc为偶数。
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <string>
#include <math.h>
#include <vector>
#include <queue>
#include <ctime>
#include <ctype.h>
#define ll long long
#define local
#define inf 0x3f3f3f3f
using namespace std;
const int N = 1005;
const int mod = 1e9 + 7;
int n,t;
char c;
int bi=0,ei=0,si=0,ii=0,gi=0,oi=0,mi=0;
int b[20],e[20],s[20],i[20],g[20],o[20],m[20];
int main()
{
#ifdef local
freopen("input.txt","r",stdin);
#endif
scanf("%d",&n);
while(n--)
{
scanf(" %c",&c);
scanf("%d",&t);
if(c=='B')
b[bi++]=t;
else if(c=='E')
e[ei++]=t;
else if(c=='S')
s[si++]=t;
else if(c=='I')
i[ii++]=t;
else if(c=='G')
g[gi++]=t;
else if(c=='O')
o[oi++]=t;
else if(c=='M')
m[mi++]=t;
}
int t1=gi*oi*ei*si;
int t2=bi*ii;
int t3=mi;
int num1=0,num2=0,num3=0;
//printf("%d %d %d\n",bi,ii,mi);
for(int i1=0; i1<gi; i1++)
{
for(int j=0; j<oi; j++)
{
for(int k=0; k<ei; k++)
{
for(int l=0; l<si; l++)
{
if((g[i1]+o[j]+e[k]+s[l])%2==0)
num1++;
}
}
}
}
for(int k=0; k<bi; k++)
{
for(int j=0; j<ii; j++)
{
if((b[k]+i[j])%2==0)
num2++;
}
}
for(int k=0; k<mi; k++)
if(m[k]%2==0)
num3++;
//(A∪B∪C = A+B+C - A∩B - B∩C - C∩A + A∩B∩C)
int ans=num1*t2*t3+t1*num2*t3+t1*t2*num3-t1*num2*num3-num1*t2*num3-num1*num2*t3+num1*num2*num3;
printf("%d",ans);
return 0;
}
参考:
【1】百度百科;
【2】https://blog.csdn.net/lxt_lucia/article/details/81066272