Light OJ 1067 Combinations (乘法逆元)
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
知识点:乘法逆元,扩展欧几里得。
题意:求C(n,m)%mod
难点:理解乘法逆元。
扩展:乘法逆元定义:如果a*b=1(mod n),那么b就是a关于模n的乘法逆元,此时,也可称作a与b互为乘法逆元。
思路:1.C(n,m)%mod=n!/m!*(n-m)!%mod除以一个数并取模等价于乘以这个数的逆元然后再去模.可将n!/m!*(n-m)!%mod等价于n!/m!%mod*1/(n-m)!%mod.再等价于n!*inv[m!]%mod(m!的逆元)*inv[(n-m)!]((n-m!)的逆元).
2.也就是说,求出逆元即可求解。c*x=1(mod n)=1-k*n等价于c*x+k*n=1所以可以用扩展欧几里得算法求得x(逆元)的值。为了保证x是正整数,通常需要加上:x=(x%n+n)%n.
1 #include<cstdlib> 2 #include<cstdio> 3 #include<iostream> 4 #include<algorithm> 5 #include<cstring> 6 using namespace std; 7 #define m 1000003 8 long long f[1000005]; 9 long long inv[1000005]; 10 long long x,y,gcd; 11 void extend_gcd(long long a, long long b) 12 { 13 if(b == 0) 14 { 15 x = 1; 16 y = 0; 17 gcd = a; 18 } 19 else { 20 extend_gcd(b, a%b); 21 long long temp = x; 22 x = y; 23 y = temp - a/b*y; 24 } 25 } 26 void factorial() 27 { 28 f[0]=1;inv[0]=1; 29 for(int i=1;i<=1000000;i++) 30 { 31 f[i]=f[i-1]*i%m; 32 extend_gcd(f[i],m); 33 inv[i]=(x%m+m)%m; 34 } 35 } 36 int main() 37 { 38 factorial(); 39 int t; 40 int cnt=0; 41 scanf("%d\n",&t); 42 int a1,b1; 43 while(t--) 44 { 45 scanf("%d%d",&a1,&b1); 46 long long ans=f[a1]*inv[b1]%m*inv[a1-b1]%m; 47 printf("Case %d: %lld\n",++cnt,ans); 48 49 } 50 51 return 0; 52 } 53 //3 54 // 55 //4 2 56 // 57 //5 0 58 // 59 //6 4 60 61 //3 62 //1 1 63 //2 3 64 //4 3