题意:
- T组数据,N个人,最少K人一个小组,问有多少种分组的方式?
思路:
- ans = 2 ^ N - ( C(N, 0) + C(N, 1) + … + C(N, K - 1));
- 其中C(n, m + 1) = n! / ((m + 1)! (n - m - 1)! ) = C(n, m) * (n - m) / (m + 1);
- 利用上面的递推公式得出 C(N, 0) 、 C(N, 1) 、 … 、 C(N, K - 1)
- 结果对1000000007取模。
注意:
- 注意输出格式
- 除法用费马小定理
- 减法注意负数:处理:ans = ( ans + p ) % p;
- 乘法C(n, m) (n - m) / (m + 1) = C(n, m) (n - m) fast_power(m + 1, p - 2)必须要分开乘,连乘会爆精度!!因为这个WA了N发!哭!
#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#define INF 0x3f3f3f3f
#define MID l + r >> 1
#define lsn rt << 1
#define rsn rt << 1 | 1
#define Lson lsn, l, mid
#define Rson rsn, mid+1, r
#define QL Lson, ql, qr
#define QR Rson, ql, qr
using namespace std;
typedef long long ll;
const ll maxN = 1e5 + 7;
const int maxM = 1e7;
const ll p = 1000000007;
ll C[maxN];
ll fast_power(ll x, ll y)
{
ll base = x % p, ans = 1;
while(y)
{
if(y & 1)
ans = (ans % p) * (base % p) % p;
base = (base % p) * (base % p) % p;
y >>= 1;
}
return ans % p;
}
int main()
{
ll T, N, K;
scanf("%lld", &T);
for(ll Case = 1; Case <= T; Case ++ )
{
scanf("%lld%lld", &N, &K);
if(N < K)
{
printf("Case #%lld: 0\n", Case);
continue;
}
C[0] = 1; C[1] = N;
ll A = fast_power(2, N) - 1;
for(ll i = 1; i < K; i ++ )
{
A = (A + p - C[i]) % p ;
C[i + 1] = (C[i] % p) * ((N - i) % p) % p;
C[i + 1] = C[i + 1] * fast_power(i + 1, p - 2) % p;
}
printf("Case #%lld: %lld\n", Case, A);
}
return 0;
}