C++基础数论————容斥原理

前言:

     温馨提示,此篇博客将涉及排列组合(链接)。

概念:

      在计数时,必须注意没有重复,没有遗漏。为了使重叠部分不被重复计算,人们研究出一种新的计数方法,这种方法的基本思想是:先不考虑重叠的情况,把包含于某内容中的所有对象的数目先计算出来,然后再把计数时重复计算的数目排斥出去,使得计算的结果既无遗漏又无重复,这种计数的方法称为容斥原理

《C++基础数论————容斥原理》

      好了,我们理解概念,开始例题吧。

例题一:

描述:

        一年级某班有30人,考了语文和数学,语文上90的有17人,数学上90的有25人,语文和数学同时上90的有15人。问有多少同学两门课都没有上90?

答案:

     3人。

分析:

    如图,上了语文90分的人和上了语文90分的人的和重复了语文和数学同时上的人,所以是:30-17-25+15=3人。

《C++基础数论————容斥原理》

例题二:

描述:

       假设班里有50名学生,每个人都必须选修一门运动科目,选修篮球的有15人,选修足球的有20人,选修乒乓球的有30人,同时选修篮球和足球的有10人,同时选修乒乓球和足球的有18人,同时选修篮球和乒乓球的有12人,问选修了三门科目的有多少人?

答案:

       无解。

分析:

   WHAT?!!你的心里一定是这样想的。

  别急我们分析一下:

  选修篮球的加选修足球的加选修乒乓球的减去同时选修篮球和足球的和同时选修乒乓球和足球的与同时选修篮球和乒乓球的就是

  班里人数减去三门都选修了的。

  所以应是25人。

  可是,选修篮球的就只有15人,那么多的10人从何而来呢?

  所以无解。

《C++基础数论————容斥原理》

例题三:

描述:

你是一个喜欢编程的手机经销商,一次你得到了一个边长为n的正方体箱子,里面装满了长,宽,高为a,b,c的华为手机盒,手机盒均朝同一方向摆放。这时,一束阳光正好照过正方体箱子的对角线,你想知道,这一束阳光穿过了多少手机盒。

(n<=100000,a,b,c均为n的约数)。

输入:

输入4个正整数,分别表示n,a,b,c。

输出:

输出光束穿过手机盒的数量。

输入样例:

10 5 2 2

输出样例:

6

思路分析:

我们先从二维平面开始讲,因为从对角线穿过,所以它只会穿过上底和右高(从左上到右下)。

那么穿过长的条数为n/a,宽的条数为n/b,但是会穿过顶点,而它又被加了两次,所以减去n/lcm( a , b)。

lcm指的是最小公倍数

来到三维也是这个操作。

就是:n/a+n/b+n/c-n/lcm(a,b)-n/lcm(b,c)-n/lcm(a,c)+n/lcm(lcm(b,c),a))。

代码实现:

#include<cstdio>
#include<iostream>
#include<algorithm>
long long n,a,b,c;
long long gcd(long long x,long long y)
{
    if(!y)
        return x;
    else
    {
        r=gcd(y,x%y);
        return r;
    }
}
long long lcm(long long x,long long y)
{
    return x*y/gcd(x,y);
}
int main()
{
    scanf("%lld%lld%lld%lld",&n,&a,&b,&c);
    printf("%lld",n/a+n/b+n/c-n/lcm(a,b)-n/lcm(b,c)-n/lcm(a,c)+n/lcm(lcm(b,c),a));
}

 

点赞