扑克牌
题目描述
组合数学是数学的重要组成部分,是一门研究离散对象的科学,它主要研究满足一定条件的组态(也称组合模型)的存在、计数以及构造等方面的问题。组合数学的主要内容有组合计数、组合设计、组合矩阵、组合优化等。
随着计算机科学的日益发展,组合数学的重要性也日渐凸显,因为计算机科学的核心内容是使用算法处理离散数据。
今天我们来研究组合数学中的一个有趣的问题,也是一个简单的计数问题:
从一副含有 n n n 张的扑克牌(每张扑克牌都不相同)中,分给 m m m 个人,第 i i i 个人得到 a i a_i ai 张牌,求一共有几种分法,这个数可能非常大,请输出此数模 10007 10007 10007 后的结果。
输入格式
第一行两个整数为 n , m n,m n,m。
第二行 m m m 个整数 a i a_i ai。
输出格式
此数模 10007 10007 10007 后的结果。
样例 #1
样例输入 #1
5 2
3 1
样例输出 #1
20
样例 #2
样例输入 #2
20 19
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
样例输出 #2
8707
提示
对于 50 % 50\% 50% 的数据: M = 1 M=1 M=1。
对于 100 % 100\% 100% 的数据: 1 ≤ n ≤ 1 0 4 1 \leq n \leq 10^4 1≤n≤104, 1 ≤ m ≤ 100 1 \leq m \leq 100 1≤m≤100, 0 ≤ a i ≤ 100 0 \leq a_i \leq 100 0≤ai≤100。
解析
res计算组合数即可
代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=1e4+5,mod=10007;
int n,m;
int fact[N],infact[N];
//快速幂
int qmi(int a,int k,int p){
int res=1;
while(k){
if(k&1) res=res*a%p;
a=a*a%p;
k>>=1;
}
return res;
}
//预处理
void init(){
fact[0]=infact[0]=1;
for(int i=1;i<N;i++){
fact[i]=fact[i-1]*i%mod;
infact[i]=infact[i-1]*qmi(i,mod-2,mod)%mod;
}
}
void solve(){
scanf("%d%d",&n,&m);
init();
int res=1;
for(int i=1;i<=m;i++){
int x;
scanf("%lld",&x);
res=res*(fact[n]*infact[x]%mod*infact[n-x]%mod)%mod;
n-=x;
}
printf("%lld",res);
}
signed main(){
int t=1;
// scanf("%lld",&t);
while(t--) solve();
return 0;
}