【20211027 模拟赛】庆典
Statement
【题目描述】 战狂在昌和帝国的首都法法城召开了庆典,向一万名最杰出的士 兵分发了用魔法猪做的猪肉饺子,士兵们吃了猪肉饺子后,战斗力大 幅提高。 为了保护战狂的安全以及维护现场秩序,大预言家抽调了 n 名普 通士兵组成了 m 个小队完成一些不同的任务。由于一些特殊的原因, 所有小队的人数都互不相同。 你需要求出有多少种可能的组队方案。注意士兵是相同的,而小 队是不同的。
【输入数据】 第一行两个个整数 n,m。
【输出数据】 一行一个数表示答案。对 998244353 取模。
【样例输入】 16 4 【样例输出】 216
【数据范围】 对于 20%的数据,n,m<=20。 对于 50%的数据,n,m<=3000。 对于 100%的数据,n,m<=100000
Solution
题目即是问把 \(n\) 个相同的球放到 \(m\) 个不同的箱子里面,要求每个箱子里面球的数量不同,方案数
为了满足球数不同的要求,我们考虑先给第 \(i\) 个箱子放 \(i\) 个球(很妙的手段)
假设剩下了 \(n^{\prime}\) 个球,接下来的操作手段显然是说每次可以把一个后缀整体增加 \(1\)
这其实成为了一个类似完全背包的问题,总容量 \(n^{\prime}\) ,物品体积 \(1\dots n^{\prime}\) ,数量无限。
不要忘了箱子不同,答案要乘一个 \(m!\)
还有另外一个想法是说,这其实是一个 整数划分问题
Code
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N = 1e5+5;
const int mod = 998244353;
void file(){
freopen("celebration.in","r",stdin);
freopen("celebration.out","w",stdout);
}
int read(){
int s=0,w=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9')s=s*10+ch-'0',ch=getchar();
return s*w;
}
int f[N];
int n,m;
signed main(){
n=read(),m=read();
if(2*n<m*(m+1))puts("0");
else{
n-=m*(m+1)/2;
f[0]=1;
for(int i=1;i<=m;++i)
for(int j=i;j<=n;++j)
(f[j]+=f[j-i])%=mod;
for(int i=1;i<=m;++i)(f[n]*=i)%=mod;
printf("%lld\n",f[n]);
}
return 0;
}