1. 程式人生 > >Light OJ 1067 Combinations (費小馬定理求逆元)

Light OJ 1067 Combinations (費小馬定理求逆元)

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

Output for Sample Input

3

4 2

5 0

6 4

Case 1: 6

Case 2: 1

Case 3: 15

 費小馬定理求逆元

a/b=1mod( M );

只要 M 是一個素數,而且 b 不是 M 的倍數,就可以用一個逆元整數 b’,通過 a/b=a*b'*(mod M)來以乘換除

費馬小定理說,對於素數 M 任意不是 M 的倍數的 b,都有:b^(M-1)=1 (mod) M;

於是可以拆成:b*b^(M-2)=1(mod)M;

所以:a/b=a/b*(b*b^(M-2))=a*(b^(M-2))(mod M)

也就是說我們要求的逆元就是b^(M-2)(mod M)

#include<stdio.h>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=1e6+5,mod=1000003;
typedef long long LL;
LL fact[maxn];//不明白為什麼這裡我用define定義maxn就不行 
void f()//打出階乘表 
{
    fact[1]=fact[0]=1;
    for(LL  i=2;i<maxn;i++)
    fact[i]=(i*fact[i-1])%mod;
}
LL niyuan(LL a,LL p)//快速冪
{
    LL res=1%mod;
	LL t=a%mod;
	while(p)
	{
		if(p%2)
		res=res*t%mod;
		t=t*t%mod;
		p=p/2;
	}
	return res;
}
LL c(int n,int k)
{
    LL fm=(fact[k]*fact[n-k])%mod;
    LL ans1=niyuan(fm,mod-2);//費馬小定理,求一個冪就好;
    return (ans1*fact[n])%mod;
}
int main()
{
    int t,n,k,kase=0;
    f();
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&k);
        if(k*2>n)
        k=n-k;//組合數對稱性,減少計算;
        printf("Case %d: %lld\n",++kase,c(n,k));
    }
    return 0;
}