It is said that a dormitory with 6 persons has 7 chat groups ^_^. But the number can be even larger: since every 3 or more persons could make a chat group, there can be 42 different chat groups.
Given N persons in a dormitory, and every K or more persons could make a chat group, how many different chat groups could there be?
Input
The input starts with one line containing exactly one integer T which is the number of test cases.
Each test case contains one line with two integers N and K indicating the number of persons in a dormitory and the minimum number of persons that could make a chat group.
- 1 ≤ T ≤ 100.
- 1 ≤ N ≤ 109.
- 3 ≤ K ≤ 105.
Output
For each test case, output one line containing "Case #x: y" where x is the test case number (starting from 1) and y is the number of different chat groups modulo 1000000007.
Example
Input
1
6 3
Output
Case #1: 42
题意:n个人的小组,最少m个可以组成一组,问共有多少种方法。
思路:就是求C(n,k) + C(n,k+1) +...+ C(n,n);但是数据量超大,我们可以转换一下
2^n - ( C(n,0) + C(n,1) + ... + C(n,k-1) )而C(n,k) = ( n*(n-1)*..(n-k+1) ) / ( k! );因为要除以k的阶乘,所以就用到了费马小定理求逆元,除以一个很大的数就是乘以它的逆元。最好是把逆元预处理一下就不会超时了。
用费马小定理求逆元
费马小定理公式:a^(p-1) ≡ 1(mod p)
逆元公式:H * B ≡ 1 (mod M) -->这里假设M为质数,由公式显然B与M互质
其中M = p,B = a
联立可得H * a ≡ a^(p - 1)(mod p)
同时除以a(显然a mod p 不为0)
最终得B(或者a)关于p的逆元
H ≡ a^(p - 2)(mod p)
AC代码:
/***
* ┌───┐ ┌───┬───┬───┬───┐ ┌───┬───┬───┬───┐ ┌───┬───┬───┬───┐ ┌───┬───┬───┐
* │Esc│ │ F1│ F2│ F3│ F4│ │ F5│ F6│ F7│ F8│ │ F9│F10│F11│F12│ │P/S│S L│P/B│ ┌┐ ┌┐ ┌┐
* └───┘ └───┴───┴───┴───┘ └───┴───┴───┴───┘ └───┴───┴───┴───┘ └───┴───┴───┘ └┘ └┘ └┘
* ┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───────┐ ┌───┬───┬───┐ ┌───┬───┬───┬───┐
* │~ `│! 1│@ 2│# 3│$ 4│% 5│^ 6│& 7│* 8│( 9│) 0│_ -│+ =│ BacSp │ │Ins│Hom│PUp│ │N L│ / │ * │ - │
* ├───┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─────┤ ├───┼───┼───┤ ├───┼───┼───┼───┤
* │ Tab │ Q │ W │ E │ R │ T │ Y │ U │ I │ O │ P │{ [│} ]│ | \ │ │Del│End│PDn│ │ 7 │ 8 │ 9 │ │
* ├─────┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴─────┤ └───┴───┴───┘ ├───┼───┼───┤ + │
* │ Caps │ A │ S │ D │ F │ G │ H │ J │ K │ L │: ;│" '│ Enter │ │ 4 │ 5 │ 6 │ │
* ├──────┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴────────┤ ┌───┐ ├───┼───┼───┼───┤
* │ Shift │ Z │ X │ C │ V │ B │ N │ M │< ,│> .│? /│ Shift │ │ ↑ │ │ 1 │ 2 │ 3 │ │
* ├─────┬──┴─┬─┴──┬┴───┴───┴───┴───┴───┴──┬┴───┼───┴┬────┬────┤ ┌───┼───┼───┐ ├───┴───┼───┤ E││
* │ Ctrl│ │Alt │ Space │ Alt│ │ │Ctrl│ │ ← │ ↓ │ → │ │ 0 │ . │←─┘│
* └─────┴────┴────┴───────────────────────┴────┴────┴────┴────┘ └───┴───┴───┘ └───────┴───┴───┘
*/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<vector>
#include<algorithm>
#include<map>
#include<cmath>
using namespace std;
#define inf 0x3f3f3f3f
#define PI acos(-1)
const int mod=1e9+7;
const int M=1e5 + 10;
typedef long long ll;
ll a[M]={0};
ll F(ll a, ll b)
{
ll ans = 1;
a %= mod;
while(b){
if(b&1)
ans = ((a%mod) * ans) % mod;
a = (a * a) % mod;
b >>= 1;
}
return ans % mod;
}
void init(){//预处理逆元
ll p = 1;
for (ll i = 1; i <= 1e5;i++){
p = (p * i) % mod;
a[i] = F(p, mod - 2) % mod;
if(a[i]<0)
a[i] += mod;
}
}
int main()
{
ll T, n, k;
init();
scanf("%lld", &T);
for (int kk = 1; kk <= T; kk++)
{
scanf("%lld%lld", &n,&k);
ll ans = F(2, n) - 1;//先减去C(n,0)的情况
ll p = 1, q = 1;
for (ll i = 1; i < k; i++){
p = ((p % mod) * (n - i + 1)) % mod;
q = (q * i) % mod;
ans = ans - (p % mod * (a[i] % mod)) % mod;
if (ans < 0)
ans += mod;
}
printf("Case #%d: %lld\n", kk, ans%mod);
}
return 0;
}