【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;
}
posted @ 2021-10-27 17:05  _Famiglistimo  阅读(65)  评论(0编辑  收藏  举报