要计算几个集合并集的大小,我们要先将所有单个集合的大小计算出来,然后减去所有两个集合相交的部分,再加回所有三个集合相交的部分,再减去所有四个集合相交的部分,依此类推,一直计算到所有集合相交的部分。

简单来说,就是奇加偶减。

20190402164825432.png

举个例子:

求1~n中多少个数不是2,3,5,7的倍数,当n=10,结果只有1一个数。

#include<iostream>
using namespace std;
int main()
{
	int n;
	cin>>n;
	int ans=n-(n/2+n/3+n/5+n/7)+(n/2/3+n/2/5+n/2/7+n/3/5+n/3/7+n/5/7)-(n/2/3/5+n/2/3/7+n/3/5/7+n/2/5/7)+n/2/3/5/7;
	//ans=n-(n/2+n/3+n/5+n/7)+(n/6+n/10+n/14+n/15+n/21+n/35)-(n/30+n/42+n/105+n/70)+n/210
	cout<<ans<<endl;
	return 0;
} 

例子2:

题目描述:
V_Dragon有n盏电灯泡,编号为1-n,每个灯泡都有一个开关,那么问题来了

  1. 所有灯泡初始时为不亮的;
  2. V_Dragon分别进行三次操作;
  3. 每次操作他都选一个质数x,将编号为x和x的整数倍的灯泡的开关都拨动一下(如果灯为亮,那么拨动以后灯为不亮,如果灯不亮,拨动以后变为亮)

求最后亮着的灯的数量;

输入:
输入T表示T组测试数据(1<=T<=100)
接下来T组数据
每组第一行一个n表示灯泡各数(1<=n<=109)
第二行三个数a,b,c表示V_Dragon每次选择的数(1<=a,b,c<=10
6)(a,b,c全为质数且a,b,c两两互不相等)

输出:
最后亮着的灯的个数

样例输入:

1
30
2 3 5

样例输出:

15

题解:

原来的方法:
a+b+c-(ab+ac+bc)+abc。这祥的话a+b+c代表的是啊a,b,c总的要按的灯的按钮。
而ab,bc,ac代表的是按两次或者两次以上灯的数量。
这里我们应该想一下,如果只是减一个ab+ac+bc的话,那就是三次所涉及的总共灯的数量,
但是对一个灯操作两次,灯就关了。这祥就不需要计算这一块了。所以应该减两次ab+ac+bc。
再看+abc。我们将在前面已经-2*(ab+bc+ac)了,就相当于将abc这一块减了三次,
但是对于abc这一块,三次操作还是亮着的。所以应该加上4*(abc)。
所以最后的公式应该是a+b+c-2(ab+bc+ac)+4abc.

#include<iostream>
using namespace std;
int main()
{
	int T,n,a,b,c;
	cin>>T;
	while(T--)
	{
		cin>>n;
		cin>>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);
		//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 
		cout<<sum<<endl;
	}
	return 0;
}