XidianOJ 1149 卡尔的技能 II

--正文

多重集合数 + 组合数取模

首先求出没有限制的选择方法C(n+m-1,m)

然后减掉至少有一个元素选择了k+1次的方法数,加上至少有两个元素选择了k+1次的方法数。。。以此类推

然后是组合数的计算

   C(n,m) % p= (n! / (m! * (n-m)!)) % p 

由乘法逆元的性质和费马小定理可以算出

   C(n,m)  % p= n! * (m!*(n-m)!)^(p-2)

后面的幂次使用快速幂可以轻松算出

#include <cstdio> 
#include <cstring> 
#include <algorithm> 
#include <cmath> 
#include <iostream> 
using namespace std;  
typedef long long LL;
#define MOD 1000000007
LL Fast_Mod(LL a,LL b){
    LL res = 1,base = a;
    while (b){
        if (b&1) res = (res*base) % MOD;
        base = (base*base) % MOD;
        b = b >> 1;
    }
    return res;
}
LL fac[2000009],invfac[2000009],n,m,k;
void Getfac(LL p){
    fac[0] = 1;
    int i;
    for (i=1;i<=p;i++){
        fac[i] = (fac[i-1]*i) % MOD;
    }
    invfac[p] = Fast_Mod(fac[p],MOD-2);
    for (i=p-1;i>=0;i--){
        invfac[i] = (invfac[i+1]*(i+1)) % MOD;
    }
}
LL Lucas(LL n,LL m){
    if (n < m) return 0;
    return ((fac[n] % MOD)*(invfac[m] % MOD) % MOD) * (invfac[n-m] % MOD) % MOD;
}
int main(){ 
  Getfac(2000006);
  while(scanf("%lld %lld %lld",&n,&m,&k)!=EOF){ 
     long long i;
     long long res = Lucas(n+m-1,m),sign = -1;
     for (i=1;i<=n;i++,sign = -sign){
         long long tmp = m - (k+1)*i; 
         if (tmp < 0) break;
        res = (res % MOD + sign*Lucas(n,i)*Lucas(n+tmp-1,tmp)) % MOD;
     }
     printf("%lld\n",(res+MOD) % MOD);
  } 
  return 0; 
} 

 

转载于:https://www.cnblogs.com/ToTOrz/p/6171359.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值