容斥原理及其应用

首先我们先来说什么是容斥原理?

容斥原理:先不考虑重叠的情况,把包含于某内容中的所有对象的数目先计算出来,然后再把计数时重复计算的数目排斥出去,使得计算的结果既无遗漏又无重复,这种计数的方法称为容斥原理。(来源于百度)

主要公式:

两个集合的容斥关系公式:A∪B =|A∪B| = |A|+|B| - |A∩B|

三个集合的容斥关系公式:|A∪B∪C| = |A|+|B|+|C| - |A∩B| - |B∩C| - |C∩A| + |A∩B∩C|

应用:有一根长为n厘米的绳子,从一端开始每隔x厘米做一个记号,每隔y厘米做一个记号,然后将有记号的地方剪断,问这条绳子现在一共被剪成了几段。

思路:隔x厘米剪断一次时,这条绳子被剪断成k1段,n/x=k1;

           隔y厘米剪断一次时,这条绳子被剪断成k2段,n/y=k2;

           能被隔x厘米剪断又可以被隔y厘米剪断的:即为x与y的最小公倍数c,即n/c=k3;

      (一)难点:按正常来说绳子一共被剪成的段数为sum=k1+k2-k3段,但是这个题由于要考虑最后端点是否为x或y或c的倍数二分情况讨论。(如果绳子的末端端点被标记的话实际上是不需要截断的)

我现在以n分别为9、10、11、12厘米来分析,x=2y=3c=6

9cm

——.——.*——#——.*——.——#*——.——.*——.   

x=2不过末端

y=3过末端

c=6不过末端

图像上:一共被截成了6段

纯计算:sum=k1+k2-k3=4+3-1=6

图像与计算相符合

                                                        10cm

                                                        ——.——.*——.#——.*——.——.*#——.——.*——.#——.*

                                                        x=2过末端

                                                        y=3不过末端

                                                        c=6不过末端

                                                        图像上:一共被截成了7段

                                                        纯计算:sum=k1+k2-k3=5+3-1=7

                                                        图像与计算相符合

11cm

——.——.*——.#——.*——.——.*#——.——.*——.#——.*——.

x=2不过末端

y=3不过末端

c=6不过末端

图像上:一共被截成了8段

纯计算:sum=k1+k2-k3=5+3-1=7

图像与计算相不符合

出现该现象的原因即为x,y是否过末端

                                 12cm

                                 ——.——.*——.#——.*——.——.*#——.——.*——.#——.*——.——.*#

                                x=2过末端

                                y=3过末端

                                c=6过末端

                                图像上:一共被截成了8段

                                纯计算:sum=k1+k2-k3=6+4-2=8

                                图像与计算相符合

我之所以以n为9、10、11、12为例,是因为这四个数字正好包含了x=2,y=3(可以任意取,只是举例这个比较明显的得到)时x、y过不过末端的所有情况,即是否能被n整除(四种情况:1.x过,y过;2.x过,y不过;3.x不过,y过;4.x不过,y不过),其中当x、y都不过末端时为特殊情况。

(二)c是x、y的最小公倍数

最小公倍数的求法:最小公倍数*最大公约数=x*y;

r=x%y;
	o=x*y;
	while(r!=0)
			{
				x=y;
				y=r;
				r=x%y;
			} 
				c=o/y;	

所以这个程序的总代码:

#include<bits/stdc++.h>
using namespace std;
int main(){
	int n,x,y,c,r,o;
	cin>>n>>x>>y;
	int k1,k2,k3,sum=0;
	k1=n/x;
	k2=n/y;
	r=x%y;
	o=x*y;
	if(n%x==0||n%y==0)//x、y中只要有一个可以被n整除 ,那么图像数量与计算数量相符合 
		{
			while(r!=0)
			{
				x=y;
				y=r;
				r=x%y;
			} 
				c=o/y;
				k3=n/c;
				sum=k1+k2-k3;
				cout<<sum;
		}
		
		
	else
		{
			while(r!=0)
			{
				x=y;
				y=r;
				r=x%y;
			} 
				c=o/y;
				k3=n/c;
				sum=k1+k2-k3+1;//x、y都不被整除时,实际的绳子段数比计算出来的结果多1 
				cout<<sum;
		}
} 

我是以分情况的,这种方法比较麻烦,有很多代码都是重复的,因为我把所有的东西都写到了一个函数里。

另一种方法:代码量较少

#include<bits/stdc++.h>
using namespace std;
int gcd(int a,int b)
{
	int m;
	m=a%b;
	while(m!=0)
	{
		a=b;
		b=m;
		m=a%b;
	}
	return b;//求最大公约数b 
}
int main(){
	int n,x,y,c;
	cin>>n>>x>>y;
	bool f=true;
	c=x*y/gcd(x,y);//c为最小公倍数 
	if(n%x==0||n%y==0)
	  f=false;//将只要x、y有一个可以被n整除的情况设为bool函数中true的情况(也可以不设的,直接分情况写) 
	if(f==true)
	  cout<<n/x+n/y-n/c+1<<endl;
	else
	  cout<<n/x+n/y-n/c<<endl;
	return 0;
} 

两个写法的思路都是一样的。

有什么不会的可以私我~

  • 4
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值