首先我们先来说什么是容斥原理?
容斥原理:先不考虑重叠的情况,把包含于某内容中的所有对象的数目先计算出来,然后再把计数时重复计算的数目排斥出去,使得计算的结果既无遗漏又无重复,这种计数的方法称为容斥原理。(来源于百度)
主要公式:
两个集合的容斥关系公式: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=2;y=3,c=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;
}
两个写法的思路都是一样的。
有什么不会的可以私我~