第一个转自:九野的博客,转载请注明出处:http://blog.csdn.net/acmmmm/article/details/12318011
组合数:
公式递推代码
C(n, m) = C(n -1, m - 1) + C(n - 1, m)
const int M = 10007; //注意M是 取模
const int MAXN = 1000;
int C[MAXN+1][MAXN+1];
void Initial()
{
int i,j;
for(i=0; i<=MAXN; ++i)
{
C[0][i] = 0;
C[i][0] = 1;
}
for(i=1; i<=MAXN; ++i)
{
for(j=1; j<=MAXN; ++j)
C[i][j] = (C[i-1][j] + C[i-1][j-1]) % M;
}
}
int Combination(int n, int m)
{
return C[n][m];
}
上面的很耗费空间,其实C(5,3) == C(5,2),C(5,1) == C(5,4)所以这样可以构造省空间型
int c[5000 + 5][2500 + 5];
void C() {
for(int i=0; i<=5000; ++i) {
c[i][0] = 1;
}
c[1][1] = 1;
for(int i=2; i<=5000; ++i)
for(int j=1; j<=i/2; ++j)
c[i][j] = (c[i-1][min(j - 1,i - j)] + c[i-1][min(j,i - j - 1)]) % MOD;
}
直接求函数型,因为除法对取模有影响,但是可以转为乘法,也就是乘法逆元
来自:http://www.cnblogs.com/woaishizhan/archive/2013/08/13/3254590.html
ll exgcd(ll a, ll b, ll &x, ll &y) {
if(!b) {
x = 1; y = 0;
return a;
}
ll r = exgcd(b, a%b, y, x);
y -= a/b*x;
return r;
}
ll inv(ll a, ll m)
{
ll x,y,gcd = exgcd(a, m, x, y);
if(x < 0)
x += m;
return x;
}
ll C(ll n,ll m) {
ll ans = 1;
for(int i=1;i<=m;i++)
ans = ((ans * inv(i,MOD))%MOD * (n - i + 1))%MOD;
return ans;
}
跟上一个差不多的,看N,M的值分别来行事而已
ll exgcd(ll a, ll b, ll &x, ll &y) {
if(!b) {
x = 1; y = 0;
return a;
}
ll r = exgcd(b, a%b, y, x);
y -= a/b*x;
return r;
}
ll inv(ll a, ll m)
{
ll x,y,gcd = exgcd(a, m, x, y);
if(x < 0)
x += m;
return x;
}
ll C(ll n,ll m)//计算组合数C(n,m)
{
ll t1=1,t2=1;
for(LL i=n;i>m;i--)
{
t1=(t1*i)%MOD;
t2=(t2*(i-m))%MOD;
}
return t1*inv(t2,MOD)%MOD;
}
lucs定理模版,用于求 C(n,m)%p,p为素数
int inv(int a) {
return a == 1 ? 1 : (ll)(MOD - MOD / a) * inv(MOD % a) % MOD;
}
ll C(ll n,ll m)
{
if(m < 0)return 0;
if(n < m)return 0;
if(m > n-m) m = n-m;
ll up = 1, down = 1;
for(ll i = 0 ; i < m ; i ++){
up = up * (n-i) % MOD;
down = down * (i+1) % MOD;
}
return up * inv(down) % MOD;
}
ll lucas(ll n,ll m,ll p)
{
ll ret = 1;
while(n && m){
ll a = n % p,b = m % p;
if(a < b)return 0;
ret = ret * C(a,b) % p;
n /= p;
m /= p;
}
return ret;
}