[DP记录]ABC221H Count Multiset

command_block

2021-11-19 07:18:47

Personal

**题意** : 对于每个 $k=1\sim n$ ,统计满足以下要求的无序集合个数: - 元素均为正整数。 - 恰有 $k$ 个元素。 - 同一个数最多出现 $m$ 次 - 元素和为 $n$。 答案对 $998244353$ 取模。 $m\leq n\leq 5000$ ,时限$\texttt{2s}$ 。 ------------ 对于一种方案,将集合中的数从大到小排列,画出直方图。 直方图的上边缘是一条路径,要求如下: - 从左侧某处出发 - 单调不升 - 围成面积为 $n$ - 最多横向连续移动 $m$ (这个横过来不好做) - 恰横向移动了 $k$ 将该图像转置,仍然得到一条路径,要求如下: - 从左侧下方某处出发 - 围成面积为 $n$ - 最多纵向连续移动 $m$ - 恰纵向移动了 $k$ 考虑 DP ,记 $f[S][x]$ 为下方面积为 $S$ ,目前高度为 $x$ 的方案数。 枚举上一行的高度,转移如下: $$f[S][x]=\sum\limits_{y=\max(1,x-m)}^xf[S-x][y]$$ 前缀和优化,复杂度 $O(n^2)$。 ```cpp #include<algorithm> #include<cstdio> #define MaxN 5050 using namespace std; const int mod=998244353; int n,m,f[MaxN][MaxN],o[MaxN][MaxN]; int main() { scanf("%d%d",&n,&m); o[0][0]=1; for (int s=1;s<=n;s++){ for (int x=1;x<=s;x++){ f[s][x]=o[s-x][min(x,s-x)]; if (x-m-1>=0)(f[s][x]-=o[s-x][min(x-m-1,s-x)])%=mod; o[s][x]=(o[s][x-1]+f[s][x])%mod; } } for (int i=1;i<=n;i++) printf("%d\n",(f[n][i]+mod)%mod); return 0; } ```