LightOJ1067Combinations(逆元)

来源:互联网 发布:知乎邮箱注册地址 编辑:程序博客网 时间:2024/06/04 17:47
Description
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

题意:给你n个数,问你从中取k个数有多少种取法。

思路:这道题根据题意可以很容易推出答案是c(n,k)。这时我们会想到同余定理,但是同余定理对于a/b不适用。那怎么做呢?这就要用到费马小定理了。费马小定理(Fermat Theory)是数论中的一个重要定理,其内容为: 假如p是质数,且gcd(a,p)=1,那么 a(p-1)≡1(mod p)。即:假如a是整数,p是质数,且a,p互质(即两者只有一个公约数1),那么a的(p-1)次方除以p的余数恒等于1。这里要用的是a的(p-1)次方除以p的余数恒等于1,那么a的(p-2)次方对p取余就等于a的-1次方对p取余了。知道这个后就好做了。首先打表把每个数的阶层求出来,然后快速幂求的k的p-2次方和n-k的p-2次方,再用同余定理求出结果!

代码:

#include<cstdio>
#include<string.h>
#include<math.h>
using namespace std;
#define ll long long
ll n,k,g=1000003;
ll ch[1000010];
ll quickpow(ll x,ll y,ll h)//快速幂取余
{
ll ans=1;
while(y)
{
if(y&1)
ans=(ans*x)%h;
x=(x*x)%h;
y>>=1;
}
return ans%h;
}
void j()//阶层打表
{
ll i=0;
ch[0]=1;
ch[1]=1;
for(i=2;i<=1000000;i++)
ch[i]=(ch[i-1]*i)%g;
}
int main()
{
ll t,l=1;
scanf("%lld",&t);
j();
while(t--)
{
ll sum=0;
scanf("%lld%lld",&n,&k);
ll q=0,w=0,e=0;
q=ch[n];
w=quickpow(ch[n-k],g-2,g);
e=quickpow(ch[k],g-2,g);
sum=(((q*w)%g)*e)%g;
printf("Case %lld: %lld\n",l++,sum);
}
return 0;
}

0 0
原创粉丝点击