FZU 2020 Comb(拡張ユークリッド求逆元)

1300 ワード

yimao兄の組み合わせ数を求めて余りのテンプレートを取って、姿勢を上げました(¯▽¯)
/*
      ;

C(n,m)= n*(n-1)*...*(n-m+1) / m!;
     ,m   10^4,1s   (     10^7),         ;

  : fz:     :fz= n*(n-1)*...*(n-m+1);  10^4   ,
      ;

  : fm:     :fm= m*(m-1)*...*2*1;  10^4   ,
      ;

         p         ;
*/

#include <cstdio>
#include <iostream>
using namespace std;

int ext_gcd(int a, int b, int &x, int &y){
    if( !b ) return x=1,y=0,a;
    int d= ext_gcd(b, a%b, y, x);
    y-= a/b*x;
    return d;
}
int Inv(int a, int m){
    int d,x,y;
    d= ext_gcd(a,m,x,y);
    return (x%m+m)%m;
}

/*     C(n,m)%p,  m<=10^4,p   , m<p;
fm:     :fm= m*(m-1)*...*2*1;
fz:     :fz= n*(n-1)*...*(n-m+1);

           ,
      (   )   p   ,     ;
C(n,m)= n*(n-1)*...*(n-m+1) / m!;
C(n,m)%p = (fz%p) * Inv( (fm%p), p ) %p;

*/
long long Comb(int n, int m, int p){
    long long fm=1, fz= 1;
    for(int i=2; i<=m; ++i)
        fm= fm*i%p;
    for(int i=n-m+1; i<=n; ++i)
        fz= fz*i%p;
    long long ret= fz * Inv( fm, p ) %p;
    return ret<0 ? ret+p : ret;
}

int main()
{
    //freopen("E.in","r",stdin);
    int T,n,m,p;
    cin>>T;
    while( T-- ){
        cin>>n>>m>>p;
        cout<< Comb( n, m, p ) <<endl;
    }
}