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; }