【20211027 模擬賽】慶典
阿新 • • 發佈:2021-10-27
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; }