想比大家对组合数都十分了解了
下文我们都直接用C(n,m)来表示了
正常组合数
杨辉三角
在学习组合数的时候,老师肯定会讲杨辉三角的,所以这里也不多累赘了。
int comb[N][N];
void init()
{
for(int i=0;i<N;i++;i++)
{
comb[i][0]=comb[i][i]=1;
for(int j=1;j<;j++)
comb[i][j]=comb[i-1][j]+comb[i-1][j-1];
}
}
代码只是简单的打表而已。复杂度O(n^2)
直接求法
毕竟是有直接的数学公式的,C(n,m)=n!/m!/(n-m)!
所以只要打表出每一个数的阶乘,然后遍历一遍暴力求就行,复杂度O(n)
但是总所周知怎么又是众所周知 ,阶乘是很大的,比如20!= 2432902008176640000
所以一般来说要用逆元来求,一般这种题是要求取模的,所以用两个数组一个存阶乘的逆元一个存阶乘就行了
但如果题目没取模怎么办,问题不大,自己取一个比较大的质数当模数就好了。
int F[N],Finv[N],inv[N];
//inverse element : 逆元
//factorial :阶乘
//Finv 阶乘的逆元
void init()
{
inv[1] = 1;
for(int i=2;i<N;i++)
inv[i]=(mod-mod/i)*1ll*inv[mod%i]%mod;
F[0]=Finv[0]=1;
for(int i = 1;i<N;i++)
{
F[i]=F[i-1]*1ll*i%mod;
Finv[i] = Finv[i-1]*1ll*inv[i]%mod:
}
}
//C(n,m)
int comb(int n,int m)
{
if(m<0 || m>n)return 0;
return F[n]*1ll*Finv[n-m]%mod*Finv[m]%mod;
}
但其实这其实是别人博客里的代码,这里安利一下这个大佬的博客,也是一个数论的专题,我觉得写的很好。
镜外之主
如果觉得我写的不好的话可以看这个大佬的博客哇(然后大家都不来看我的了,嘤嘤嘤)
大组合数–Lucas定理
Lucas定理就一行公式
C(n, m) % p = C(n / p, m / p) * C(n%p, m%p) % p
这就可以处理n和m都很大但p1比较合理的情况下的组合数了。
ll lucas(ll n,ll m,ll p)
{
return m?lucas(n/p,m/p,p)*comb(n%p,m%p,p)%p:1;
}
原理的话在写了,真的再写了,咕是不可能咕,在路上了咕
CRT(论p不是素数怎么办)
咕咕咕
注意,p得是质数 ↩︎