Given n different objects, you want to take k of them. How many ways to can do it?
For example, say there are 4 items; you want to take 2 of them. So, you can do it 6 ways.
Take 1, 2
Take 1, 3
Take 1, 4
Take 2, 3
Take 2, 4
Take 3, 4
Input
Input starts with an integer T (≤ 2000), denoting the number of test cases.
Each test case contains two integers n (1 ≤ n ≤ 106), k (0 ≤ k ≤ n).
Output
For each case, output the case number and the desired value. Since the result can be very large, you have to print the result modulo 1000003.
Sample Input
3
4 2
5 0
6 4
Sample Output
Case 1: 6
Case 2: 1
Case 3: 15
两种方法可求解,不过感觉大致上是差不多的。。。
题意:数学组合问题改编成费马小定理—>逆元。。。组合 C(n,m) = n! / (m! * (n - m)! )
逆元:由费马小定理a ^ (p-1) = 1 (%p),两边同时除去a——a ^ (p-2) = a^-1 (%p),得a的逆元a^-1 = a ^ (p-2)。
题解:当n 不大于 1e6 时可以考虑打表,先把每个数的介乘打表,再把每个数的逆元打表,然后就出来答案了
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define M 1000003
#define LL long long
LL pre[M], pows[M];
void init()//将每个数的介乘打表
{
pre[0] = 1;
for(int i=1; i<M; i++)
{
pre[i] = pre[i-1] * i % M;
}
}
LL quickpow(LL n, LL m, LL k)//用快速幂求逆元
{
LL res = 1;
while(m)
{
if(m & 1)
{
res = res * n % k;
}
m >>= 1;
n = n * n % k;
}
return res;
}
void init2()//将每个数的介乘的逆元打表
{
pows[0] = 1;
pows[1] = 1;
for(LL i=2; i<M; i++)
{
pows[i] = quickpow(pre[i], M-2, M);//传入数据是每个数的介乘
}
}
int main()
{
int t;
LL ans, n, m, a, b, c;
scanf("%d", &t);
init();
init2();
for(int ca=1; ca<=t; ca++)
{
scanf("%lld%lld", &n, &m);
a = pre[n];
b = pows[m];
c = pows[n-m];
ans = (a * c % M) * b % M;
printf("Case %d: %lld\n", ca, ans);
}
return 0;
}
lucas定理求解。。。。。lucas大模板题
根据百度可知:C(n,m)%p=C(n/p,m/p)*C(n%p,m%p)%p链接在此
然后就可以开始我们构造函数之路了
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define LL long long
#define M 1000003
LL fac[M];
void fact()//构造阶乘
{
fac[0] = 1;
for(int i=1; i<M; i++)
{
fac[i] = fac[i-1] * i % M;
}
}
LL quickpow(LL n, LL m, LL k)//快速幂
{
LL res = 1;
while(m)
{
if(m & 1)
{
res = res * n % k;
}
m >>= 1;
n = n * n % k;
}
return res;
}
LL comb(LL n, LL m, LL k)//这个是组合函数
{
LL ans = 1;
ans = fac[n] * quickpow(fac[m]*fac[n-m]%k, k-2, k) % k;
return ans;
}
LL lucas(LL n, LL m, LL k)//这个是lucas
{
LL ans = 1;
if(m > n) return 0;//这个应是显然咯
while(n && m && ans)
{
ans = ans * comb(n%k, m%k, k);
n /= k;
m /= k;
}
/*
return comb(n%k, m%k, k) * lucas(n/k, m/k, k);递归方法
*/
return ans;
}
int main()
{
int t;
LL n, m;
fact();
scanf("%d", &t);
for(int ca=1; ca<=t; ca++)
{
scanf("%lld%lld", &n, &m);
printf("Case %d: %lld\n", ca, lucas(n, m, M));
}
return 0;
}