ABC221H Count Multiset

[ABC221H] Count Multiset


以下内容多引用自 [1] 对应的文章


分拆数

表示将 正整数 \(N\) 拆成 若干正整数 和的 方案数 \(P_N\),可以形式化的表示成 以下方程的解的个数

\[x_1 + x_2 + ... + x_m = N, 1 \le x_1 \le x_2 \le ... \le x_m \]

其中我们通常将每个正整数 \(x_i\) 称作 一个部分

注意到 分拆数 的定义中 不要求顺序,这里为方便运算 人为规定了大小顺序,不影响正确性

注意到 分拆数 严格意义上形式化为 不升序列的和,但为方便书写,以下采用 不降序列和 的形式

这里给出前面分拆数的一个表

\(N\) \(0\) \(1\) \(2\) \(3\) \(4\) \(5\) \(6\) \(7\) \(8\) \(9\) \(10\)
\(P_N\) \(1\) \(1\) \(2\) \(3\) \(5\) \(7\) \(11\) \(15\) \(22\) \(30\) \(42\)

\(K\) 部分拆数

即表示将 正整数 \(N\) 拆成 \(K\) 个正整数 和的 方案数 \(P_{N, K}\),可以形式化的表示成 以下方程的解的个数

\[x_1 + x_2 + ... + x_K = N, 1 \le x_1 \le x_2 \le ... \le x_K \]

我们可以注意到存在

\[P_N = \sum_{K = 1} ^ N P_{N, K} \]

改写一下 上面的方程,有

\[x_1 + x_2 + ... + x_k = N - K, 0 \le x_1 \le x_2 \le ... \le x_K \]

于是当 \(x_1, x_2, ... , x_K\) 中有 \(i\) 个数 \(0\) 时,显然方程将有 \(P_{N - K, i}\) 个解,于是有下式

\[P_{N, K} = \sum_{i = 0} ^ K P_{N - K, i} \]

于是 相邻两式做差有

\[P_{N, K} - P_{N - 1, K - 1} = \sum_{i = 0} ^ K P_{N - K, i} - \sum_{i = 0} ^ {K - 1} P_{(N - 1) - (K - 1), i} \\ = \sum_{i = 0} ^ K P_{N - K, i} - \sum_{i = 0} ^ {K - 1} P_{N - K, i} \\ = P_{N - K, K} \]

即有如下递推式

\[P_{N, K} = P_{N - 1, K - 1} + P_{N - K, K} \]

于是我们可以在 \(O(N ^ 2)\) 的复杂度内求得任意 \(P_{N, K}\)

for (int i = 1; i <= N; ++ i)
    for (int j = 1; j <= i; ++ j) 
        F[i][j] = F[i - 1][j - 1] + F[i - j][j]

\(Ferrers\)

上面的式子应当有一些 组合意义,我们可以这样描述 其中一种

显然我们需要构造一个 不降序列 \(x_1, x_2, ... , x_k\) 使得其 和为 \(k\)

构造该序列 一共只需要下面两步

  1. 在序列前方插入 \(1\)\(eg. ~ 2 ~ 3 ~ 4 \to 1 ~ 2 ~ 3 ~ 4\)
  2. 给序列整体加 \(1\)\(eg. ~ 2 ~ 3 ~ 4 \to 3 ~ 4 ~ 5\)

可以证明,所有的 不降序列 都可以通过 上述两步执行若干次 后得到

同时其对于 整个序列的数和 的影响分别是 \(+1\)\(+N\)\(N\)序列项数

对于 整个序列的项数 的影响分别是 \(+1\)\(+0\)

回到递推式 \(P_{N, K} = P_{N - 1, K - 1} + P_{N - K, K}\),现在就好理解了

\(P_{N - 1, K - 1}\) 代表的就是 执行 \(1\) 操作后 可以得到合法序列的种数

\(P_{N - K, K}\) 代表的就是 执行 \(2\) 操作后 可以得到合法序列的种数

两者求和,正确性显然

而这里也有一种 思路相似图形转化 方式,即 \(Ferrers\)

我们将分拆的 每部分点行 表示,每行点数 就是 这个部分的大小

根据其 严格定义\(Ferrers\) 图 按点数递减次序摆放,最长的一行在顶部

\(eg. ~ 10 = 5 + 2 + 2 + 1\)\(Ferrers\)

⚪ ⚪ ⚪ ⚪ ⚪
⚪ ⚪
⚪ ⚪
⚪

将一个 \(Ferrers\) 沿 左上 - 右下 对角线 反转后 将得到新的 \(Ferreres\) 图,也称为 原图的共轭

\(eg. ~ 10 = 5 + 2 + 2 + 1\)\(Ferrers\) 图的共轭(即 \(10 = 4 + 3 + 1 + 1 + 1\)\(Ferrers\) 图)

⚪ ⚪ ⚪ ⚪
⚪ ⚪ ⚪
⚪
⚪
⚪

我们可以由此得到分拆数的 一个性质

自然数 \(N\)最大部分为 \(K\)分拆数个数 等于 \(P_{N, K}\),即 \(N\)\(K\) 部分拆数

同时,我们可以在 \(Ferrers\) 图上 形象化 刚刚 构造不降序列两个操作

  1. 在序列前面插入 \(1\),即是 在图下方插入一个点,行数 \(+1\)

    \(eg. ~ 2 ~ 3 ~ 4 \to 1 ~ 2 ~ 3 ~ 4\)

    . . . .          . . . .
    . . .      ->    . . .
    . .              . .
                     .
    
  2. 给序列整体 \(+1\),即是 在图左边插入一列,行数不变

    \(eg. ~ 2 ~ 3 ~ 4 \to 3 ~ 4 ~ 5\)

    . . . .          . . . . .
    . . .      ->    . . . .
    . .              . . .
    

于是操作反过来就是 砍掉下面一个独立点砍掉左边一列(没有独立点时)

而递推式 \(P_{N, K} = P_{N - 1, K - 1} + P_{N - K, K}\) 即对应如下

⚪ ⚪ ... ⚪ ⚪            
⚪ ⚪ ... ⚪ ⚪           
...                     
⚪ ⚪                     
⚪
⚪
    
共 N 个点,K 行     

⚪ ⚪ ... ⚪ ⚪
⚪ ⚪ ... ⚪ ⚪
...
⚪ ⚪
⚪
    
砍独立点,剩 N - 1 个点,K - 1 行

⚪ ... ⚪ ⚪
⚪ ... ⚪ ⚪
...
⚪

砍左一列,剩 N - K 个点,K 行(没有独立点时)

注意到 实际上\(N - K\) 个点,\(K\) 行,左边插入一列 得到的 \(N\)\(K\)

故显然对应情况 没有独立点正确性不受影响


回到原题

我们发现无非是 \(K\) 部分拆数 多了一个 每个元素出现次数不超过 \(M\) 的要求

想想我们 不降序列 的构造过程,整体 \(+1\) 显然 不影响相同元素出现次数的最大值

也就是只有 插入 \(1\) 这一步 可能导致相同元素出现超过 \(M\)

容易发现,我们只需要保证(插入 \(1\))后,\(1\) 出现次数不超过 \(M\) 即可

正难则反,考虑容斥,也就是将 所有情况求出后 减去 \(1\) 出现 \(M + 1\) 次的情况

注意到 \(1\)一个一个插入的,也就是我们只需保证 \(1\) 不会出现 \(M + 1\) 次即可

不用考虑出现 \(M + 2...M + N\) 次的情况

回到 \(Ferrers\) 图,我们发现如果存在 \(M + 1\)\(1\),则最左边将有 \(M + 1\) 个独立点

此时我们 暴力将最左边一列 砍掉,显然总点数少了 \(K\),行数少了 \(M + 1\)

于是新图对应的分拆数即是 \(P_{N - K, K - (M + 1)}\)将这部分减掉就是正确的递推式了

\[F_{i, j} = F_{i - 1, j - 1} + F_{i - j, j} - F_{i - j, j - (M + 1)} \]

给个代码

#include <bits/stdc++.h>

const int MAXN = 5005;
const int MOD  = 998244353;

using namespace std;

long long F[MAXN][MAXN];

int N, M;

int main () {
	
	cin >> N >> M;
	
	F[0][0] = 1;
	
	for (int i = 1; i <= N; ++ i)
		for (int j = 1; j <= i; ++ j) 
			F[i][j] = (F[i - 1][j - 1] + F[i - j][j] - (j > M ? F[i - j][j - (M + 1)] : 0) + MOD) % MOD;
		
	for (int i = 1; i <= N; ++ i) cout << F[N][i] << '\n';
	
	return 0;
}

引用

[1] 分拆数 - OI Wiki (oi-wiki.org)

posted @ 2024-03-07 16:49  FAKUMARER  阅读(16)  评论(1)    收藏  举报