zoukankan      html  css  js  c++  java
  • 卢卡斯定理学习笔记

    卢卡斯定理

    是一个不用懂证明只记结论的定理

    首先我们学卢卡斯定理之前,需要了解的一个东西逆元

    逆元博客讲解传送门
    在这里,我们需要用到线性求逆元的方法。

    我们知道组合数公式$$C^n_m=frac{n!}{m!(n-m)!}$$
    卢卡斯定理的公式是

    [C^m_n=prod^k_{i=0}C^{m_i}_{n_i}pmod p \ n=n_{k}p^{k}+n_{k-1}p^{k-1}+dots +n_{1}p+n_0 \ m=m_{k}p^{k}+m_{k-1}p^{k-1}+dots +n_{1}p+n_0 \ ]

    这样将组合数的求解分解为小问题的乘积,下面考虑计算C(ni, mi) %p.

    已知(C(n, m) mod p = frac{n!}{m!(n - m)!} mod p)。当我们要求(a/b)mod p的值,且b很大,无法直接求得a/b的值时,我们可以转而使用乘法逆元k,将a乘上k再模p,即(a*k) mod p。 其结果与(a/b) mod p等价。

    于是,简单的代码就这样出现了

    #include <iostream>
    #include <algorithm>
    #include <queue>
    #include <cstring>
    #include <cstdio>
    #define LL long long
    using namespace std;
    int k,n,m,p;
    LL inv[100005],fac[100005];
    LL lucas(int x,int y) {
    	if(x<y) return 0;
    	else if(x<p) return fac[x]*inv[y]*inv[x-y]%p;
    	else return lucas(x/p,y/p)*lucas(x%p,y%p)%p;
    }
    void get() {
    	inv[1]=1;
    	fac[1]=1;
    	fac[0]=1;
    	inv[0]=1;
    	for(int i=1; i<=n+m; i++)fac[i]=fac[i-1]*i%p;
    	for(int i=2; i<=n+m; i++)inv[i]=(p-p/i)%p*inv[p%i]%p;
    	for(int i=2; i<=n+m; i++)inv[i]=inv[i-1]*inv[i]%p;
    }
    int main() {
    	scanf("%d%d%d",&n,&m,&p);
    	get();
    	printf("%d
    ",lucas(n,m)%p);
            return 0;
    }
    
  • 相关阅读:
    mongodb 配置单实例与双实例
    redis 集群 搭建
    memcached 搭建
    公网yum 源地址
    jdk 安装
    activemq 搭建--集群
    zookeeper 安装
    activemq 安装-单点
    rabbitmq 集群
    python——网络编程
  • 原文地址:https://www.cnblogs.com/ifmyt/p/9776655.html
Copyright © 2011-2022 走看看