题目链接:
C-岗位分配_河南萌新联赛2024第(四)场:河南理工大学 (nowcoder.com)
题目描述:
学校马上要举行校运会了,有众多志愿岗位需要被分配。但是负责老师临时有事现在由你来分配这些岗位。
现在有n个岗位,m位志愿者,每个岗位至少需要ai个志愿者,你需要将志愿者分配到岗位上,并且可以有志愿者空闲下来作预备。
请你给出可能的分配情况总数。
答案可能会很大,故需要对998,244,353取模。
注:所有岗位需求志愿者的总和不超过志愿者的总和且志愿者间无差别。
输出描述:
一个数字,表示可能的分配情况总数。
示例1
输入:
3 10 1 2 3
输出:
35
思路:
他首先要先满足n个岗位的需求,满足之后呢还会有剩余的人,这道题问的安排的可能其实就是剩余的人如何安排,剩余的人可以有除了n个岗位以外,还有无业人员,一共n+1,种去处,这n+1种去处是不同的,而题干志愿者是相同的,假设剩余了r个志愿者,其实就是将r个相同的志愿者安排给n+1个不同的位置,可以为空。因为可以将志愿者全安排出去,这样剩0个人无业人员,也可以全安排给一个岗位,这就说明安排可以为空,抽象模型的话就是,将n个相同的小球放进m个不同的盒子内。
这明显是一道排列组合的问题,那么怎么安排就尤为重要了,只要看出他是怎么安排的,剩下的只要将排列组合的模板套进去就可以了。我们看一共有m位志愿者,n个岗位需要分配,每个岗位至少需要a[i]人,先满足每个岗位所需的a[i] 个人后,剩余的人,有n种选择,因为其说所有岗位需求志愿者的总和不超过志愿者的总和且志愿者间无差别,因此套用球盒模型的话,就相当于将 n 个相同的小球放入 m个不同的盒子当中,且允许有空格
19. 球盒问题 — fong alpha documentation (fangyq.cn)
这是大佬写的博客,你们可以自己去看看理解一下这个公式是怎么推到出来的,如果觉得比较难以理解的话
【高中数学】球与盒子的故事——8种球盒模型你拎得清吗?_哔哩哔哩_bilibili
这里有B站的视频,用具体的数字来辅助理解
关于组合数的求解,这道题的数据范围比较小,n和m都是 10的3次幂的量级,我们使用递推,杨辉三角来解决,对于一个组合数
选当前数
不选当前数
求组合数的代码:
void init()
{
for(int i=0;i<N;i++)
{
for(int j=0;j<=i;j++)
{
if(j==0) C[i][j]=1;
else C[i][j]=(C[i-1][j-1]+C[i-1][j])%mod;
}
}
}
代码实现:
#include<bits/stdc++.h>
using namespace std;
const int N=2005;
const int mod=998244353;
int C[N][N];
void init()
{
for(int i=0;i<N;i++)
{
for(int j=0;j<=i;j++)
{
if(j==0) C[i][j]=1;
else C[i][j]=(C[i-1][j-1]+C[i-1][j])%mod;
}
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
init();
int n,m;
cin>>n>>m;
vector<int> a(n);
for(int i=0;i<n;i++)
{
cin>>a[i];
m-=a[i];
}
cout<<C[m+n][n]<<endl;
return 0;
}