题意:一个宿舍中又n个人,最少k(k >= 3)个人就可以建一个讨论组,问最多可以建多少个不同的讨论组。
解答:C(n,k)+C(n,k+1)+.......+C(n,n) = 2^n - ( C(n,0) + C(n,1) + C(n,2) + ......+C(n,k-1) )
知识点:费马小定理求逆元inv(a) = qpow( a, mod-2 )。 阶乘逆元:https://blog.csdn.net/Tc_To_Top/article/details/51203160
1 //C(n, k) + C(n, k + 1) + ....... + C(n, n) = 2 ^ n - (C(n, 0) + C(n, 1) + C(n, 2) + ...... + C(n, k - 1)) 2 #define MAXN 100005 3 #define mod 1000000007 4 int t; 5 int n, k; 6 ll inv[MAXN]; 7 ll fac[MAXN], coeff[MAXN]; 8 ll QPow(ll x, ll n){ //快速幂计算 9 ll ret = 1; 10 ll tmp = x % mod; 11 while (n){ 12 if (n & 1) { 13 ret = (ret * tmp) % mod; 14 } 15 tmp = tmp * tmp % mod; 16 n >>= 1; 17 } 18 return ret; 19 } 20 void init(){ 21 fac[0] = 1; 22 //fac数组是阶乘 23 for (int i = 1; i < MAXN; i++) { 24 fac[i] = fac[i - 1] * i % mod; 25 } 26 27 // 费马小定理求逆元inv(a) = qpow( a, mod-2 ) 28 // inv数组存储k阶乘关于模mod的逆元 29 inv[MAXN - 1] = QPow(fac[MAXN - 1], mod - 2); 30 for (int i = MAXN - 2; i >= 0; i--) { 31 //inv[i] = inv[i + 1] * (i + 1) % mod; 32 inv[i] = QPow(fac[i], mod - 2); 34 } 35 } 36 int main() { 37 cin >> t; 38 init(); 39 for(int tn = 1;tn <= t; tn++) { 40 cin >> n >> k; 41 ll ans = (QPow(2, n) - 1 + mod) % mod; 42 coeff[0] = 1; 43 for (int i = 1; i < k; i++) { 44 // (a / b) % mod = a *(b关于模mod的逆元)% mod; 45 // C(n,k)=(n-k+1)/k * C(n,k-1) k从1走到k-1 46 // C(n,1)=C(n,0)*(n-1+1)/1 C(n,2)=C(n,1)*(n-2+1)/2 C(n,3)=C(n,2)*(n-3+1)/3 47 // 令a =coeff[k]=(n-k+1) * C(n,k-1) b=k 48 // C(n,k) = coeff[k] / k! 49 50 coeff[i] = coeff[i - 1] * (n - i + 1) % mod; 51 ans = (ans - coeff[i] * inv[i] % mod + mod) % mod; 52 } 53 printf("Case #%d: %lld ", tn, ans); 54 } 55 return 0; 56 }