组合数学(上)

博客探讨了鸽笼原理及其在高中排列组合、Ramsey理论、数论问题(如斐波那契数列)中的应用。通过实例解析了如何利用鸽笼原理解决生日悖论、握手问题以及在分糖问题上的应用。还介绍了快速幂和矩阵快速幂方法在计算大数斐波那契数列项时的作用,并提供了相关代码示例。此外,提到了容斥原理在埃氏筛法中的应用。
摘要由CSDN通过智能技术生成

鸽笼原理

定理:将n+1个物品放进n个盒子至少一个盒子含有2个及以上的物品。
抽象:将n个物品进行k次划分产生k+1个区间至少有n-k个区间含有n/k个物品
(高中排列组合里的隔板法)
比如:有1500人过生日,至少5人同生日;n个人握手,一定有两人握手次数相同

HDU1205“分糖”
思路:设总糖数位sum,找出n种中数目最大的哪一种,数目设为max。根据鸽笼原理,把max视为挡板的话。
如果满足max数小于sum-max<max-1那么说明必定有两个数目最大种类的糖放在一起了。
否则,必定可以。

拓展:鸽笼原理实际是ramsey原理的特判
ramsey:6个人中至少三个人认识或者至少三个人不认识具体题目:hdu5917
思路:
当节点小于6暴力枚举n的5次幂
大于等于6直接C(m ,n)m是选定子集的节点数,n是总数

杨辉三角和二项式系数

知识点:排列组合公式,二项式系数公式,二项式系数关系
排列组合公式:
请添加图片描述

二项式系数公式:
对于(ax+b)^n 其中第k项的系数为:C(k-1,n)*a(n-k-1) *bk-1
二项式系数和杨辉三角的关系:
杨辉三角第n行第k项对应C(k,n)

容斥原理

简单来讲就是去重
比如:在埃氏筛法中我们删去非素数时是按倍数删,6是2的倍数也是3的倍数被重复删了两次自然要加回来一次。
重点在推导公式

超大菲波那切数列项

HDU3117

主要运用了数论的知识,包括对数原理和快速幂原理。

要求:输出1e9内的斐波那契数,由于斐波那契数增长十分迅速所以当数大于8位时我们只要输出这个数的前四位和后四位就好。

思路:前四位和后四位时两种做法。前四位:数论利用对数和菲波那切数列通项公式实现。后四位:利用矩阵快速幂和公式实现,由于快速幂过程中得到的数还是会非常大,所以还要进行取模操作

通项公式:
请添加图片描述

快速幂公式:
请添加图片描述

代码:
前四位

#include <bits/stdc++.h>

using namespace std;

int main()
{
    double s=(sqrt(5.0)+1.0)/2.0
    double ans=-0.5*log(5.0)/log(10.0)+((double)n)*log(s)/log(10.0);
    ans-=floor(ans);
    ans=pow(10.0,ans);
    while(ans<1000)
        ans*=10;
    cout<<ans<<endl;
    return 0;
}

原理:我们利用举个例子
假设给出一个数10234432,那么log10(10234432)=log10(1.0234432*10^7)=log10(1.0234432)+7
log10(1.0234432)就是log10(10234432)的小数部分.

log10(1.0234432)=0.010063744

10^0.010063744=1.023443198
于是就可以只取前面的1023了

后四位:

#include <bits/stdc++.h>
#define mod 100000000+7;
using namespace std;
struct Matrix
{
    long long data[2][2];
};
Matrix f={1,0,0,0};
Matrix ini={1,1,1,0};
Matrix Matrix_Multi(Matrix a,Matrix b)
{
    Matrix res;
    for(int i=0;i<2;i++)
    {
        for(int j=0;j<2;j++)
        {
            for(int k=0;k<2;k++)
            {
                res.data[i][j]+=a.data[i][k]*b.data[k][j]%mod;
                res.data[i][j]%=mod;
            }
        }
    }
    return res;
}
long long fast_pow(int n)
{
     Matrix a=f,b=ini;
    while(n)
    {
        if(n&1)
        a=Matrix_Multi(a,b);
        b=Matrix_Multi(b,b);
        n>>=1;
    }
    return ((a.data[0][0])%1000);
}
int main()
{
    int n;
    cin>>n;
    long long ans=fast_pow(n);
    cout<<ans<<endl;
    return 0;
}

原理:矩阵相乘

这里给出了很多数学方法,理解起来其实并不困难,难的是将这些方法用于具体题目中

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值