zoukankan      html  css  js  c++  java
  • 线性预处理阶乘,逆元和组合数

    证明过程见此文

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

    阶乘的递推式非常好想,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
    ",C(n,m));
    

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

  • 相关阅读:
    grep: Linux基础命令及用法 -- grep
    [功能集锦] 003
    [功能集锦] 002
    [mysql相关集锦] 001
    [eclipse中使用Git插件] 008
    [eclipse相关] 001
    [代码优化集锦]
    [功能集锦] 001
    [java基础] 002
    [java基础] 001
  • 原文地址:https://www.cnblogs.com/tqr06/p/10684917.html
Copyright © 2011-2022 走看看