一本通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
【提示】
数据范围与提示:
对于所有数据,1≤m≤n≤109,m≤104,m<p<109,p 是素数。
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('\n') 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 */
河田は河田、赤木は赤木……。
私は誰ですか。教えてください、私は誰ですか。
そうだ、俺はあきらめない男、三井寿だ!