luogu P1358 扑克牌

题目描述

组合数学是数学的重要组成部分,是一门研究离散对象的科学,它主要研究满足一定条件的组态(也称组合模型)的存在、计数以及构造等方面的问题。组合数学的主要内容有组合计数、组合设计、组合矩阵、组合优化等。

随着计算机科学的日益发展,组合数学的重要性也日渐凸显,因为计算机科学的核心内容是使用算法处理离散数据。

今天我们来研究组合数学中的一个有趣的问题,也是一个简单的计数问题:

从一副含有n(n≤10000)张的扑克牌[显然每张扑克牌都不相同]中,分给m(m≤100)个人,第i个人得到ai (0≤ai≤100)张牌,求一共有几种分法,这个数可能非常大,请输出此数模10007后的结果。

输入格式

第一行两个整数 为 n m

第二行 m个整数 ai

输出格式

此数模10007后的结果


n个不同物品,m个组,每个组有容量,求物品放置方案数

ans=C(a[1],n)C(a[2],n-a[1])C(a[3],n-a[1]-a[2])...

简化一下

ans=$\prod_{i=1}^m$C(a[i],n-sum[i-1])

预处理C数组,然后按照公式算就可以了

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int mod=10007,N=1e4+5;
#define int long long
int n,m,a[N],sum[N];
int jc[N],inv[N];
inline int ksm(int x,int y){int ans=1;while(y){if(y&1)ans=ans*x%mod;x=x*x%mod;y>>=1;}return ans;}
int C(int x,int y){if(x>y)return 0;return jc[y]*inv[x]%mod*inv[y-x]%mod;}
inline void pre(){
    jc[0]=1;for(int i=1;i<=n;i++)jc[i]=jc[i-1]*i%mod;
    inv[n]=ksm(jc[n],mod-2);
    for(int i=n-1;i>=0;i--)inv[i]=inv[i+1]*(i+1)%mod;
}
signed main(){
    cin>>n>>m;pre();
    for(int i=1;i<=m;i++)scanf("%lld",&a[i]),sum[i]=sum[i-1]+a[i];
    int ans=1;
    for(int i=1;i<=m;i++)
    ans=(ans*C(a[i],n-sum[i-1]))%mod;
    cout<<ans<<endl;
}

猜你喜欢

转载自www.cnblogs.com/naruto-mzx/p/11768441.html
今日推荐