组合数

组合数就是高中排列组合的知识,求解组合数C(n,m),即从n个相同物品中取出m个的方案数。

求解方式

求解通式:$C^{m}_{n}=\dfrac {n!}{m!\left( n-m\right) !}$

性质1:$C^{m}_{n}=C_{n}^{n-m}$

性质2:$C^{m}_{n}=C^{m-1}_{n-1}-i+C^{m}_{n-1}$

打表递推

根据性质2:$C^{m}_{n}=C^{m-1}_{n-1}+C^{m}_{n-1}$

组合数算出来特别大,往往都会要求取余,这里取$P=1e9+7$。时间复杂度$O(n^2)$

;
#define N 1000
int comb[N][N];

int main() {
    ; i < N; i++) {
        comb[i][] = comb[i][i] = ;
        ; j < i; j++) {
            comb[i][j] = comb[i - ][j] + comb[i - ][j - ];
            comb[i][j] %= P;
            //cout << comb[i][j] << endl;
        }
    }
}

逆元法

因为大部分题都有求余,可利用逆元的原理(没求余的题目,自己找一个比较大的素数作为P,也可以用逆元做)

线性递推求逆元

当$p$为质数时有$a^{-1}=(p-[p/a])\cdot (p\%a)^{-1}\%p$

求阶乘的逆元

根据通式:$C^{m}_{n}=\dfrac {n!}{m!\left( n-m\right) !}$,有$C^{m}_{n}=n!\cdot inv[m!] \cdot inv[(n-m)!]$

设 $finv(i)=inv(i\ !)$

则根据:$finv(i-1)=\frac{1}{\ (i-1)\ !}=\frac{1}{i\ !}\times i =finv(i)\times i$

有:$finv(i) = finv(i-1)\times inv(i)$

详见:数论篇4——逆元(数论倒数)

初始化时间复杂度$O(n)$,求$C^{m}_{n}$为$O(1)$

;
;
], Finv[N+], inv[N+];//fact是阶乘,Finv是阶乘的逆元
void init() {
    inv[] = ;
    //线性递推求逆元
    ; i <= N; i++) {
        inv[i] = (P - P / i) * 1ll * inv[P % i] % P;
    }
    fact[] = Finv[] = ;
    ; i < N; i++) {
        fact[i] = fact[i - ] * 1ll * i % P;//求阶乘
        Finv[i] = Finv[i - ] * 1ll * inv[i] % P;//求阶乘的逆元
    }
}
int C(int n, int m) {//comb(n, m)就是C(n, m)
     || m > n) ;
    return fact[n] * 1ll * Finv[n - m] % P * Finv[m] % P;
}

卢卡斯定理

现在有了新问题,如果$n$和$m$非常大,$p$为素数,比如求$C_n^m \% p \ ,\ n\leqslant 10^{18},m\leqslant 10^{18},p\leqslant 10^{9}$

$C_n^m\ \%\ p  =  C(n / p, m / p) * C(n\ \%\ p, m\ \%\ p)\ \%\  p$

或者写成这样更准确$Lucas(n,m)\ \%\ p=Lucas(n/p,m/p)*C(n\ \%\ p,m\ \%\ p)\ \%\ p$

证明请看此 lucas_百度百科,没仔细看证明,所以对不对我也不知道。

写成递归,代码就这么短:

LL Lucas(LL n, LL m, int p){
         ;
}

具体C的实现要看情况。

P较小时,打表

typedef long long ll;
const int N = 1e5 ;
;//取一个小于N的素数
ll fact[P + ], inv[P + ], Finv[P + ];//阶乘打表

void init() {
    inv[] = ;
    //线性递推求逆元
    ; i <= P; i++) {
        inv[i] = (P - P / i) * 1ll * inv[P % i] % P;
    }
    fact[] = Finv[] = ;
    ; i < P; i++) {
        fact[i] = fact[i - ] * 1ll * i % P;//求阶乘
        Finv[i] = Finv[i - ] * 1ll * inv[i] % P;//求阶乘的逆元
    }
}

ll C(ll n, ll m){//组合数C(n, m) % p
    ;
    return fact[n] * Finv[n - m] % P * Finv[m] % P;
}
ll Lucas(ll n, ll m){
    ;
}

P较大时,没法打表,用快速幂算逆元

typedef long long ll;

const int N = 1e9 ;
;

ll quickPower(ll a, ll b) {
    ll res = ;
    a %= P;
    while (b) {
        )res = (res % P) * (a % P) % P;
        a = (a % P) * (a % P) % P;
        b >>= ;
    }
    return res;
}
ll inv(ll x) {//x关于p的逆元,p为素数
    );
}
ll C(ll n, ll m) {
    ;
    ll up = , down = ;//分子分母;
    ; i <= n; i++)
        up = up * i % P;
    ; i <= m; i++)
        down = down * i % P;
    return up * inv(down) % P;
}
ll Lucas(ll n, ll m) {
    );
    return C(n % P, m % P) * Lucas(n / P, m / P) % P;
}

数论篇7——组合数 & 卢卡斯定理(Lucas)的更多相关文章

  1. 卢卡斯定理Lucas

    卢卡斯定理Lucas 在数论中,\(Lucas\)定理用于快速计算\(C^m_n ~ \% ~p\),即证明\(C^m_n = \prod_{i = 0} ^kC^{m_i}_{n_i}\)其中\(m ...

  2. 【luogu P3807】【模板】卢卡斯定理/Lucas 定理(含 Lucas 定理证明)

    [模板]卢卡斯定理/Lucas 定理 题目链接:luogu P3807 题目大意 求 C(n,n+m)%p 的值. p 保证是质数. 思路 Lucas 定理内容 对于非负整数 \(n\),\(m\), ...

  3. ACM数论之旅10---大组合数-卢卡斯定理(在下卢卡斯,你是我的Master吗?(。-`ω´-) )

    记得前几章的组合数吧 我们学了O(n^2)的做法,加上逆元,我们又会了O(n)的做法 现在来了新问题,如果n和m很大呢, 比如求C(n, m) % p  , n<=1e18,m<=1e18 ...

  4. 卢卡斯定理 Lucas (p为素数)

    证明摘自:(我网上唯一看得懂的证明) https://blog.csdn.net/alan_cty/article/details/54318369 结论:(显然递归实现)lucas(n,m)=luc ...

  5. 洛谷.3807.[模板]卢卡斯定理(Lucas)

    题目链接 Lucas定理 日常水题...sublime和C++字体死活不同步怎么办... //想错int范围了...不要被longlong坑 //这个范围现算阶乘比预处理快得多 #include &l ...

  6. CRT中国剩余定理 & Lucas卢卡斯定理

    数论_CRT(中国剩余定理)& Lucas (卢卡斯定理) 前言 又是一脸懵逼的一天. 正文 按照道理来说,我们应该先做一个介绍. 中国剩余定理 中国剩余定理,Chinese Remainde ...

  7. 【数论】卢卡斯定理模板 洛谷P3807

    [数论]卢卡斯定理模板 洛谷P3807 >>>>题目 [题目] https://www.luogu.org/problemnew/show/P3807 [输入格式] 第一行一个 ...

  8. 【Luogu3807】【模板】卢卡斯定理(数论)

    题目描述 给定\(n,m,p(1≤n,m,p≤10^5)\) 求 \(C_{n+m}^m mod p\) 保证\(P\)为\(prime\) \(C\)表示组合数. 一个测试点内包含多组数据. 输入输 ...

  9. 【UOJ#275】组合数问题(卢卡斯定理,动态规划)

    [UOJ#275]组合数问题(卢卡斯定理,动态规划) 题面 UOJ 题解 数据范围很大,并且涉及的是求值,没法用矩阵乘法考虑. 发现\(k\)的限制是,\(k\)是一个质数,那么在大组合数模小质数的情 ...

随机推荐

  1. [转帖]浅谈P2P、P2C 、O2O 、B2C、B2B、 C2C的区别

    浅谈P2P.P2C .O2O .B2C.B2B. C2C的区别 https://www.cnblogs.com/zhuiluoyu/p/5481635.html 相信有很多人对P2P.P2C .O2O ...

  2. windows 安装 scrapy (python3.7)

    今天想要用scrapy爬取数据,想到原来刷过机没有这个库了就重新安装了一遍 安装scrapy 需要的东西   https://pan.baidu.com/s/1kuLvGQBG8tMTCY3WDLuU ...

  3. word 转 pfd

    转自: https://www.cnblogs.com/qiwu1314/p/6101400.html demo: public class Doc2Pdf { public static boole ...

  4. 算法:线性查找(重点isFlag标志)

    package com.atguigu; public class Main { public static void main(String[] args) { String[] arr=new S ...

  5. C++完全二叉树的权值

    #include<stdio.h> #include<stdlib.h> #include<math.h> #include<string.h> int ...

  6. C语言交换两个指针所指位置的数值

    交换指针变量x和y所指向的存储位置处存放的值,不需要第三个位置来存储临时变量.这种方式并没有性能上的优势. void replace(int *x, int *y) { *y = *x ^ *y; * ...

  7. 微信小程序:防止多次点击跳转(函数节流)

    场景 在使用小程序的时候会出现这样一种情况:当网络条件差或卡顿的情况下,使用者会认为点击无效而进行多次点击,最后出现多次跳转页面的情况,就像下图(快速点击了两次): 解决办法 然后从 轻松理解JS函数 ...

  8. 部署elasticsearch(三节点)集群+filebeat+kibana

    用途 ▷ 通过各个beat实时收集日志.传输至elasticsearch集群 ▷ 通过kibana展示日志 实验架构 名称:IP地址:CPU:内存 kibana&cerebro:192.168 ...

  9. docker 安装 sqlserver 数据库

    具备条件: 1.服务器需要大于2G内存.如果不够则可能无法正常启动,查看日志报如下错误:This program requires a machine with at least 2000 megab ...

  10. 《PHP7底层设计与源码实现》学习笔记1——PHP7的新特性和源码结构

    <PHP7底层设计与源码实现>一书的作者陈雷亲自给我们授课,大佬现身!但也因此深感自己基础薄弱,遂买了此书.希望看完这本书后,能让我对PHP7底层的认识更上一层楼.好了,言归正传,本书共1 ...