--正文
多重集合数 + 组合数取模
首先求出没有限制的选择方法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; }