c++ 数学 小总结

之前学习了一些数学的知识点,在此做一个小总结。

最大公约数(gcd)

当我们要求m,n的最大公约数时,一般来说有以下几种算法:

1.分解质因数法

将两个数分别分解质因数,然后取出所有公共质因数的最低次方相乘。例如,当m=48,n=60的时候,可以分解成:

48=2^4 * 3^1
60=2^2 * 3^1 * 5^1
gcd=2^2 * 3^1 =4*3=12

2.辗转相除法

辗转相除法,又称欧几里得算法,是一种极其快速的算法。

当我们要求m,n的最大公约数时,用n/m,可以得到它们的商x,以及余数y,也就是n=m*x+y。这个时候不难发现,当一个数k是n,m的公约数时,他也一定是y的约数(k是m的约数,那他自然就是m*x的公约数,k就自然也是y的约数),我们还可以得出,当一个数k是n,y的公约数时,他也一定是m的约数(类推)。

根据这两条性质,我们可以推出n,m的公约数集合与m,y的公约数集合相同。那么我们就可以把求m,n的最大公约数转换为求m,y的最大公约数。示例代码如下:

int gcd(int a,int b){
    if(b==0)return a;
    gcd(b,a%b);
}

扩展欧几里得算法

扩展欧几里得算法是欧几里得算法的扩展,用于计算两个整数a和b的最大公约数(GCD),同时还一定能找到满足一个等式的整数x和y,即:

ax + by = gcd(a, b)

算法原理

  1. 基本欧几里得算法:通过辗转相除法计算gcd(a,b)
  2. 扩展计算:在计算gcd的同时,记录递推关系

示例代码如下:

int exgcd(int a,int b){
    if(b==0){
        x=1;
        y=0;
        return a;
    }
    int t=x;
    x=y;
    y=t-a/b*y;
    return gcd(b,a%b);
}

最小公倍数(lcm)

在求最小公倍数时,我们可以使用最大公约数来快速解决。假设n,m的最大公约数是k,那么n,m的最小公倍数就是n*m/k。大家可以自行验证一下。

同余定理

给定一个正整数m(模数),如果两个整数a和b满足a-b能被m整除,即m|(a-b),则称a和b对于模m同余,记作a≡b(mod m)。

而该定理具有一些性质,如下:

可加性:a≡b(mod m)且c≡d(mod m) ⇒ a+c≡b+d(mod m)
可乘性:a≡b(mod m)且c≡d(mod m) ⇒ a×c≡b×d(mod m)

例如,当我们求解a^b%p时,可以转换为循环b次的ans*a%p。

当然,对于这个问题,如果b过大该怎么办?这时,我们可以使用到二进制的优化方法。示例代码如下:

while(b){
    if(b%2){
        ans=ans*(a%p)%p;
        b--;
    }else{
        a=a%p*(a%p)%p;
        b/=2;
    }
}

为什么呢?大家可以尝试一下。

计数

1.加法原理:

如果一个事件可以通过两种或两种以上互不相交的方式发生,那么发生这个事件的总可能性就是各个方式可能性的总和。

2. 乘法原理:

如果一个事件可以通过多个步骤发生,每个步骤都有不同的选择,那么总的可能性是各个步骤可能性的乘积。

3. 排列:

从 n 个人里面选择 k 个人排列的方案数 A(n,k)=n! / (n-k)!
考虑位置,第一个位置由 n 种选择,第二个位置有 n-1 种选择,第三个位置有 n-2 种选择... 第 k 个位置有 n+1-k 种选择,利用乘法原理,即为 n*(n-1)*(n-2)*...*(n+1-k)。

4. 组合:

从 n 个人里面选择 k 个人的方案数 C(n,k)=n! / ( (n-k)! k!)。
从排列的角度考虑,n 个人选择 k 个人相比排列会重复多算,会把每一次选出的 k 个人计算
多次,计算的次数是 k 个人的排列方式即 k!,因此直接将排列除以 k!即可。
从递推的角度考虑:从 n 个人选择 k 个人,先拿走一个人,那么就等于【n-1 个人选择 k
个人+不选择第 n 个人】+【n-1 选择 k-1 个人+选择第 n 个人】,因此 C(n,k)=C(n-1,k)+C(n-1,k-1)。 

以下是求排列与组合的示例代码:

排列
cin>>n>>k;
for(int i=n-k+1;i<=n;i++)num*=i;
cout<<num;
组合
cin>>n>>k;
for(int i=n-k+1;i<=n;i++)ans*=i;
for(int i=2;i<=k;i++)ans/=i;
cout<<ans;

如果大家有其他想法的,可以补充。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值