1. 杨辉三角(递推法)
时间复杂度:O( n * n )
C(n, k) = C(n - 1, k - 1) + C(n - 1, k)
预处理: C(n, 0) = 1,每一列第一个数=1,从a[0][0]开始
例题C-前缀平方和序列_牛客小白月赛97 (nowcoder.com)
代码
#include<iostream>
using namespace std;
typedef long long ll;
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
const int mod = 1e9 + 7, N = 1e3 + 10;
ll ans,cnt, n, x, a[N][N];
int main()
{
IOS;
cin >> n >> x;
while((cnt + 1) * (cnt + 1) <= x) cnt++;
a[0][0] = 1;
for(int i = 1; i <= cnt; i++)
{
a[i][0] = 1;
for(int j = 1; j <= i; j++)
a[i][j] = (a[i-1][j-1] + a[i-1][j]) % mod;
}
cout<<a[cnt][n]<<endl;
return 0;
}
2.乘阶逆元 (费马小定理)
通常和快速幂绑定在一起,是最快的做法
时间复杂度:O( n * log(n) )
预处理乘阶和乘阶的逆元
讲解费马小定理
快速幂
核心在于将指数的乘法分解为一系列的平方和乘法操作,从而减少计算的次数,
提高计算 pow(a, b ) mod 𝑚 的效率,特别是当 b 非常大时
快速幂和费马小定理的联系
利用费马小定理,可以减少快速幂算法中指数的大小,只要mod是质数,且a不被mod整除,则用 b mod (𝑝−1) 替换 b
求逆元
在模运算中,通常没有直接的除法操作,因为模运算的定义是基于整数除以一个数后的余数。逆元允许我们在模 𝑚m 的系统中执行除法操作。
计算阶乘时,直接计算阶乘可能会导致大数溢出。通过使用逆元,我们可以将组合数的计算转换为
计算C(n, k)组合数的代码
#include<iostream>
using namespace std;
typedef long long ll;
const int N = 1e5 + 10, mod = 1e9 + 7;
ll fact[N],nifact[N];
ll quick_mi(ll a, ll k)
{
ll ans = 1;
a %= mod;
while(k){
if(k & 1) {
ans = (ans * a) % mod;
}
a = (a * a) % mod;
k >>= 1;
}
return ans;
}
int main() {
int n,k;
cin>>n>>k;
fact[0] = nifact[0] = 1;
for(int i = 1; i < N; i ++)
fact[i] = fact[i - 1] * i % mod; //求阶乘
nifact[N-1] = quick_mi(fact[N-1], mod - 2) % mod;
for(int i = N-2; i >= 0; i --) {
nifact[i] = nifact[i + 1] * (i + 1) % mod;
}
ll sum = fact[n] * nifact[k] % mod * nifact[n-k] % mod;
cout<<sum;
return 0;
}