题目描述
难度分:787
输入n,m(1≤n,m≤50),k(n≤k≤n×m)。
输出有多少个数组a满足1≤a[i]≤m且Σni=1ai≤k。
由于结果可能非常大,对其模上998244353。
输入样例1
2 3 4
输出样例1
6
输入样例2
31 41 592
输出样例2
798416518
算法
记忆化搜索
状态定义
dp[i][su]前i−1个元素的和为su时,考虑构造子数组[i,n]最终可以得到的合法方案数。显然,答案就是dp[1][0]。
状态转移
对于当前元素,可以在num∈[1,m]的范围内进行枚举,状态转移方程为
dp[i][su]=Σmnum=1dp[i+1][su+num]
当i>n时,如果su≤k,就形成了一种合法的方案。
复杂度分析
时间复杂度
i的取值范围是[1,n],su的取值范围是[1,nm],因此状态数量为n2m。而状态转移的时间复杂度为O(m),因此整体的时间复杂度为O(n2m2)。
空间复杂度
额外空间复杂度就是dp数组的消耗,为状态的数量,即O(n2m)。
C++ 代码
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 55, MOD = 998244353;
int n, m, k, a[N], f[N][N*N];
int dfs(int i, int su) {
if(i > n) return su <= k? 1: 0;
int& v = f[i][su];
if(v != -1) return v;
int cnt = 0;
for(int num = 1; num <= m; num++) {
cnt = (cnt + dfs(i + 1, su + num)) % MOD;
}
return v = cnt;
}
int main() {
scanf("%d%d%d", &n, &m, &k);
memset(f, -1, sizeof(f));
printf("%d\n", dfs(1, 0));
return 0;
}