求组合数(取模)的两种方法
求组合数(取模)的两种方法
两种公式配合Lucas定理使用更佳
Pascal公式打表
由Pascal公式,可知
取二维数组 ,初始化 ; 打表即可。代码最简单,如下:
const int maxn(1005), mod(100003);
int tC[maxn][maxn]; //tC 表示 table of C
inline int C(int n, int k)
{
if(k > n) return 0;
return tC[n][k];
}
void calcC(int n)
{
for(int i = 0; i < n; i++)
{
tC[i][0] = 1;
for(int j = 1; j < i; j++)
tC[i][j] = (C(i - 1, j - 1) + C(i - 1, j)) % mod;
tC[i][i] = 1;
}
}
计算 返回内联函数 的值即可。
当然我们知道 ,所以上面的代码有很多空间和时间的浪费。可以将 二维数组转化为一维数组存储,同时,当 时终止第二层循环,新代码如下:
const int maxn(10005), mod(100003);
int tC[maxn * maxn]; //tC 表示 table of C
inline int loc(int n, int k) // C(n, k)返回在一维数组中的位置
{
int locate = (1 + (n >> 1)) * (n >> 1); // (n >> 1) 等价于 (n / 2)
locate += k;
locate += (n & 1) ? (n + 1) >> 1 : 0; // (n & 1) 判断n是否为奇数
return locate;
}
inline int C(int n, int k)
{
if(k > n) return 0;
k = min(n - k, k);
return tC[loc(n, k)];
}
void calcC(int n)
{
for(int i = 0; i < n; i++)
{
tC[loc(i, 0)] = 1;
for(int j = 1, e = i >> 1; j <= e; j++)
tC[loc(i, j)] = (C(i - 1, j) + C(i - 1, j - 1)) % mod;
}
}
显然,由于空间的限制,pascal打表的方式并不适合求取一些比较大的组合数。
所以第二种出现了
逆元法
因为 ,所以可以预处理1到n的阶乘对mod取模的结果,然后用“拓展欧几里得算法”或“费马小定理”或“欧拉定理”求 和 的逆元,然后相乘即可(乘的过程中记得取模)
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】