一本通1650【例 3】组合

1650:【例 3】组合

时间限制: 1000 ms         内存限制: 524288 KB

【题目描述】

给出组合数 C(n,m) 表示从 n 个元素中选出 m 个元素的方案数。例如 C(5,2)=10,C(4,2)=6。可是当 n,m 比较大的时候,C(n,m) 很大。于是 xiaobo 希望你输出 C(n,m)modp 的值。

【输入】

输入数据第一行是一个正整数 T,表示数据组数;

接下来是 T 组数据,每组数据有 3 个正整数 n,m,p。

【输出】

对于每组数据,输出一个正整数,表示 C(n,m)modp 的结果。

【输入样例】

2
5 2 3
5 2 61

【输出样例】

1
10

【提示】

数据范围与提示:

对于所有数据,1mn109m104m<p<109p 是素数。

sol:看上去卢卡斯过不去,其实就是一道卢卡斯模板。

卢卡斯定理 C(n,m) = C(n%p,m%p) * C(n/p,m/p),p必须是质数

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
inline ll read()
{
    ll s=0;
    bool f=0;
    char ch=' ';
    while(!isdigit(ch))
    {
        f|=(ch=='-'); ch=getchar();
    }
    while(isdigit(ch))
    {
        s=(s<<3)+(s<<1)+(ch^48); ch=getchar();
    }
    return (f)?(-s):(s);
}
#define R(x) x=read()
inline void write(ll x)
{
    if(x<0)
    {
        putchar('-'); x=-x;
    }
    if(x<10)
    {
        putchar(x+'0');    return;
    }
    write(x/10);
    putchar((x%10)+'0');
    return;
}
#define W(x) write(x),putchar(' ')
#define Wl(x) write(x),putchar('
')
int T;
inline ll Ksm(ll x,ll y,ll Mod)
{
    ll ans=1;
    while(y)
    {
        if(y&1) ans=ans*x%Mod;
        x=x*x%Mod;
        y>>=1;
    }
    return ans;
}
inline ll C(ll n,ll m,ll Mod)
{
    if(n<m) return 0;
    if(n==m) return 1;
    m=min(m,n-m);
    ll i,Jiec=1,Jiec_m=1;
    for(i=n-m+1;i<=n;i++) Jiec=Jiec*i%Mod;
    for(i=2;i<=m;i++) Jiec_m=Jiec_m*i%Mod;
    return Jiec*Ksm(Jiec_m,Mod-2,Mod)%Mod;
}
inline ll Lukas(ll n,ll m,ll Mod)
{
    ll ans=1;
    while(n&&m)
    {
        ans=ans*C(n%Mod,m%Mod,Mod)%Mod;
        n/=Mod;
        m/=Mod;
    }
    return ans;
}
int main()
{
    R(T);
    while(T--)
    {
        ll n=read(),m=read(),Mod=read();
        Wl(Lukas(n,m,Mod));
    }
    return 0;
}
/*
input
2
5 2 3
5 2 61
output
1
10
*/
View Code
原文地址:https://www.cnblogs.com/gaojunonly1/p/10519864.html