组合数(模板)
1. 利用 C[i][j] = C[i-1][j-1] + C[i][j-1] 递推求解
long long C[1000][1000]; // C[i][j] 表示 C(j,i)%mod j中取i; void Combination() { memset(C, 0x0000, sizeof(C)); for(int i = 0; i < 1000; i++) { for(int j = i; j < 1000; j++) { if(i==0) C[i][j] = 1; else if(i==j) C[i][j] = 1; else C[i][j] = (C[i-1][j-1] + C[i][j-1])%mod; } } }
2.
#define mod 1000000007 const int MAXN = 1000000+10; long long Fact[MAXN]; // Fact[i] 表示 i 的阶乘 long long ex(long long x, long long n) //return x^n { long long sum = 1; x %= mod; while(n) { if( n&1 ) sum = sum * x % mod; n >>= 1; x = x * x % mod; } return sum; } long long C(long long n, long long m) // return C(n, m) { if(m > n || m < 0) return 0; return Fact[n] * ex( Fact[n-m] * Fact[m] % mod, mod-2) % mod; // mod 为素数 } void initCombination() // 先初始化 A 数组 { Fact[0] = 1; for(int i = 1; i < MAXN; i++) { Fact[i] = Fact[i-1] * i % mod; } }
3. 有时候需要大量的次数运算某个数阶层的逆元,用 2 的方法会超时,可以先递推处理出 (1~n) 的阶乘的逆元
#define mod 1000000007 const int MAXN = 1000000+10; long long Fact[MAXN]; // Fact[i] 表示 i 的阶乘 long long Fact_Inv[MAXN]; // Fact_Inv[i] 表示 i 的阶层的模乘法逆元 long long ex(long long x, long long n) //return x^n { long long sum = 1; x %= mod; while(n) { if( n&1 ) sum = sum * x % mod; n >>= 1; x = x * x % mod; } return sum; } long long C(long long n, long long m) // return C(n, m) { if(m > n || m < 0) return 0; return ( Fact[n] * Fact_Inv[n-m] % mod ) * Fact_Inv[m] % mod; } void initCombination() // 先初始化 A 数组 { Fact[0] = 1; for(int i = 1; i < MAXN; i++) { Fact[i] = Fact[i-1] * i % mod; } Fact_Inv[MAXN-1] = ex(Fact[MAXN-1], mod-2); // mod 为素数 for(int i = MAXN-2; i >= 0; --i) { Fact_Inv[i] = Fact_Inv[i+1] * (i+1) % mod; } }