【模逆元】大组合数模运算 _CDTemplate

本文介绍了一种使用扩展欧几里得算法实现的大数模逆元及组合数计算的方法,并提供了完整的C++代码实现。该方法适用于需要进行大数同余模运算的场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >



制作起因:

便签纸上一直有这一行

【>整理模逆元 exgcd / 大数同余模运算】

今天嵌入式专业课一狠心一咬牙,把它完成!给它打上勾!于是—— 还真被我弄出来了……


模板来源:

依照以前Astar第二场的AC代码敲了半天,捣鼓出来一个大数组合数模运算代码,提供外接接口,可用部分包括:

求模逆元,扩展GCD,大数同余模运算,大数组合数计算。(转载请注明okcd00哟~)


参数说明:

T:数据组数

lim::取模的模值

Jval[x]:x的阶乘模lim后的值

n:组合数的下标

m:组合数的上标

_Ni(x,m):x对于m的模逆元

C(n,m):下标为n,上标为m的组合数


Code:

#include<cmath>  
#include<cstdio>  
#include<string>  
#include<vector>  
#include<cstring>  
#include<iostream>  
#include<algorithm>  
using namespace std;  
typedef long long ll;  
const ll lim=1000000007;  //lim := vmod
  
ll Jval[2000001];
void Jc_init() //初始化阶乘值的数组  
{  
    Jval[0]=1;  
    for(int i=1;i<=2000000;i++)  
    Jval[i]=(i*Jval[i-1])%lim;  
}  
  
//三元组gcd(a,b) == ax +by == d;     
struct gcdstruct //定义结构体存储(_Ni的计算)
{     
        ll d;    
        ll x;    
        ll y;    
};    
gcdstruct EXTENDED_EUCLID(ll a,ll b)  //EUCLID算法  
{    
    gcdstruct aa,bb;    
    if(b==0)
	{
    	aa.d = a;    
    	aa.x = 1;    
    	aa.y = 0;    
        return aa;    
    }    
    else
	{    
    	bb = EXTENDED_EUCLID(b,a%b);     
        aa.d = bb.d;    
        aa.x = bb.y;    
        aa.y = bb.x - bb.y * (a/b);    
    }    
    return aa;    
}     
      
ll _Ni(ll a,ll m)  //获得a对m的模逆元  
 {    
      ll x;    
      gcdstruct aa;    
      aa = EXTENDED_EUCLID(a,m);    
      return aa.x;    
}       
  
  
ll C(ll n,ll m) //获得C(n,m) 的组合数结果 := n!/((n-m)!*m!)
{   
    ll	Cans=	(	Jval[n]*_Ni(Jval[m],lim) +lim	) %lim;  // Get n!/m! 
    	Cans=	(	Cans*_Ni(Jval[n-m],lim) +lim   ) %lim;  	// Get Cans/(n-m)! 
    return (Cans+lim)%lim ;   
}  

int main()  
{  
    int T=0;	scanf("%d",&T); 
    ll n=0,m=0;		Jc_init();   
    for(int cnt=1;cnt<=T;cnt++)   
    {  
        scanf("%I64d%I64d",&n,&m);  
        printf("Case #%d: \n",cnt);
        cout<<"===<Jval>===\n n!="<<Jval[n]<<"; m!="<<Jval[m]<<endl;
        cout<<"===<_Ni>===\n m!^-1="<<_Ni(Jval[m],lim)
        			<<"; (n-m)!^-1="<<_Ni(Jval[n-m],lim)<<endl;
        printf("C(%d,%d) = %I64d (Mod lim)\n",n,m,C(n,m));  
    }  
      
    return 0;  
}   


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

糖果天王

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值