zoukankan      html  css  js  c++  java
  • 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
    ",&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
    ",++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
  • 相关阅读:
    java操作redis之jedis篇
    实现指定步长循环后移字符串数组算法
    【PAT Advanced Level】1006. Sign In and Sign Out (25)
    银行计算利息
    中国人、美国人、北京人
    网络子系统55_ip协议分片重组_加入ipq
    C#拦截系统消息的方法-Application.AddMessageFilter
    C#实现在Form上截取消息的两种方法
    Geek改变世界
    中国黑客传说:游走在黑暗中的精灵
  • 原文地址:https://www.cnblogs.com/ZP-Better/p/4655380.html
Copyright © 2011-2022 走看看