【数论干货】线性方法求阶乘,逆元和组合数

线性求法,即预处理出阶乘以及逆元

阶乘的递推式非常好想,fac[i]=fac[i-1]*i

    fac[0]=1;
    for(register int i=1;i<=maxn;++i)
        fac[i]=(1ll*fac[i-1]*i)%mod;

至于逆元,易证inv[i]=inv[i+1]*(i+1)

    inv[maxn]=qpow(fac[n+m],mod-2);
    for(register int i=maxn-1;i>=0;--i)
        inv[i]=(1ll*inv[i+1]*(i+1))%mod;

不过最大的逆元需要使用快速幂处理一下,就像这样

ll qpow(ll x,ll n) //x的n次方
{
    ll res=1;
    while(n)
    {
        if(n&1) res=(1ll*res*x)%mod;
        x=(1ll*x*x)%mod;
        n>>=1;
    }
    return res;
}

于是根据数学公式,组合数就非常好求了

ll C(ll n,ll m)
{
    ll res=(1ll*fac[n]*inv[m])%mod;
    return (1ll*res*inv[n-m])%mod;
}

需要注意,最好将式子拆成两部分,否则容易乘爆
(连WA8次的惨痛教训)

最后我们就可以愉快地输出了

printf("%lld\n",C(n,m));

数学证明我会写在以后的博客中

原文地址:https://www.cnblogs.com/tqr06/p/10684917.html

时间: 2024-10-14 05:52:14

【数论干货】线性方法求阶乘,逆元和组合数的相关文章

拓展欧几里得求逆元与阶乘逆元求法

目录 什么是逆元 如何求逆元 阶乘逆元 本文章内,若无特殊说明,数字指的是整数,除法指的是整除. 什么是逆元 我们称\(a\)是\(b\)在模\(p\)情况下的逆元,则有\(a \times b \equiv 1 ( mod\,\,p)\). 所以呢,我们其实可以将逆元看成一个数的相反数.所以在除以一个数的时候,就相当于乘上它的相反数. 如何求逆元 我们先来看看什么情况下有逆元. 当且仅当\(gcd(b,p)=1\)时,\(b\)在模\(p\)情况下有逆元. 这个结论可由裴蜀定理显然推得,下面一

求乘法逆元的几种方法

(数学渣,下面的文字可能有误,欢迎指教)乘法逆元的定义貌似是基于群给出的,比较简单地理解,可以说是倒数的概念的推广.记a的关于模p的逆元为a^-1,则a^-1满足aa^-1≡ 1(mod p) 加减乘与模运算的顺序交换不会影响结果,但是除法不行.有的题目要求结果mod一个大质数,如果原本的结果中有除法,比如除以a,那就可以乘以a的逆元替代. 在mod p的运算中,a存在乘法逆元当且仅当a与p互质.一般题目给的是一个大质数,所以只要a不是p的倍数,就以求乘法逆元. 目前了解到的求法有三种:1.扩展

C++ 求阶乘 四种方法

来总结下求阶乘的各种方法哈. 写在最前:①各个代码仅仅是提供了求阶乘的思路,以便在实际须要时再来编码,代码并不健壮!②各个程序都在1到10内測试正确. 代码一: #include<iostream> using namespace std; int fac(int); int main() { int n; while(cin>>n) { cout<<n<<"!= "<<fac(n)<<endl; } return

C++_第七章函数的基本知识_求阶乘的子函数_ 函数参数类型为数组_ 求数组内所有元素和、部分元素和的方法_实现了先从键盘输入到一个数组中,再用for循环取读出数组中的元素 for循环也可以用break来结束循环的

/* 第七章函数的基本知识 */ /*01)c++对于返回值有一定的限制:可以是常量.变量.指针.结构对象或表达式,但不可以是数组02)c++返回数组的方法:将数组作为结构会对象组成部分来返回03)函数遇到return则结束该函数04)如果一个函数的两房额参数类型相同,则必须分别制定每个参数的类型,而不能像声明常规变量那样,将声明组合在一起05)*/ //本代码注意double类型的写法以及double和int类型数据的转换 1 #include <iostream> 2 3 void che

求阶乘及阶乘和

1 #求阶乘方法一 2 def f1(n) 3 if n == 1 4 return 1 5 else 6 return n * f1(n-1) 7 end 8 end 9 10 #求阶乘方法二 11 def f2(n) 12 i = 1 13 while n > 0 14 i *= n 15 n -= 1 16 end 17 return i 18 end 19 20 #求1到n的阶乘之和方法一 21 sum = 0 22 (1..43).each do | x | 23 sum = sum

【GDOI 2011 DAY2 T3】零什么的最讨厌了 (快速求阶乘、中国剩余定理)

问题描述: 林记在做数学习题的时候,经常遇到这种情况:苦思冥想了很久终于把问题解出来,结果发现答案是0,久而久之林记在得到习题答案是0的时候就没有了做出一道难题的成就感.于是林记决定:以后出题,答案一定不能是0,例如求n!最低位非零数这样的习题就很不错了. 现在林记提出了一个更难一点的问题:求n!在K进制下的最低位非零数.其中K符合一些特殊的条件:K是由若干个互不相同的质数相乘得出来的,例如K=2,3,5,6,7,10…… 输入格式: 首先输入的第一行是一个整数Q,表示询问的个数. 接下来是Q个

一般筛法求素数+快速线性筛法求素数

素数总是一个比较常涉及到的内容,掌握求素数的方法是一项基本功. 基本原则就是题目如果只需要判断少量数字是否为素数,直接枚举因子2 ..N^(0.5) ,看看能否整除N. 如果需要判断的次数较多,则先用下面介绍的办法预处理. 一般的线性筛法 首先先介绍一般的线性筛法求素数 void make_prime() { memset(prime, 1, sizeof(prime)); prime[0]=false; prime[1]=false; int N=31700; for (int i=2; i<

基本递归(3)求阶乘

/* 名称:递归求阶乘: 作者:君翼坦荡荡~ 主要方法:递归 */ #include<iostream> using namespace std; //递归部分 int qiujiecheng(int i) { int sum=0; if(i==0) return 1; else sum = i * qiujiecheng(i-1); return sum; } int main( ) { int n,s; cin>>n; s=qiujiecheng(n);//调用函数 cout&

机器学习 —— 基础整理(四):特征提取之线性方法——主成分分析PCA、独立成分分析ICA、线性判别分析LDA

本文简单整理了以下内容: (一)维数灾难 (二)特征提取--线性方法 1. 主成分分析PCA 2. 独立成分分析ICA 3. 线性判别分析LDA (一)维数灾难(Curse of dimensionality) 维数灾难就是说当样本的维数增加时,若要保持与低维情形下相同的样本密度,所需要的样本数指数型增长.从下面的图可以直观体会一下.当维度很大样本数量少时,无法通过它们学习到有价值的知识:所以需要降维,一方面在损失的信息量可以接受的情况下获得数据的低维表示,增加样本的密度:另一方面也可以达到去噪