题解:AT_arc107_d [ARC107D] Number of Multisets

posted on 2024-09-29 06:07:50 | under | source

小清新题。一开始往树上想,有个 2D/1D 的 dp,不太能优化。

这题恶心在不好设计状态。我们称一个可重集合法指其元素总和为整数。需要发现一个显然但挺重要的结论,对于合法的可重集,可以让它总体乘 \(2\) 直到出现 \(1\),去掉一个 \(1\) 得到的可重集也是合法的。

这样就出现了子问题结构,考虑 \(f_{i,j}\) 表示可重集元素个数为 \(i\)、总和为 \(j\) 的方案数。对于 \(f_i\),首先计算最大元素为 \(1\) 的方案数,即 \(f_{i,j}\gets f_{i-1,j-1}\);然后计算最大元素为 \(\frac 12\) 的方案数,\(f_{i,\frac j2}\gets f_{i,j}\),前提是 \(2\mid j\),对于 \(\frac 14,\frac 18\dots\) 同理,可以像完全背包一样从大到小转移。

最后答案为 \(f_{n,m}\),复杂度 \(O(n^2)\)

代码

#include<bits/stdc++.h>
using namespace std;

#define int long long
const int N = 3e3 + 5, mod = 998244353;
int n, m, f[N][N];

signed 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];
		for(int j = i; j; --j)
			if(j % 2 == 0) f[i][j / 2] = (f[i][j / 2] + f[i][j]) % mod; 
	}
	cout << f[n][m];
	return 0;
}
posted @ 2026-01-15 08:14  Zwi  阅读(4)  评论(0)    收藏  举报