题目内容
原题链接
构造一个长度为 n n n 的整数数组 a a a ,满足如下两个条件:
- 1 ≤ a i ≤ m 1\leq a_i\leq m 1≤ai≤m
- ∑ a i ≤ k \sum a_i\leq k ∑ai≤k
问可以构造出多少种不同的数组 a a a 。
数据范围
- 1 ≤ n , m ≤ 50 1\leq n,m\leq 50 1≤n,m≤50
- n ≤ k ≤ n × m n\leq k\leq n\times m n≤k≤n×m
题解
经典的动态规划。
状态定义
d p [ i ] [ j ] dp[i][j] dp[i][j] 表示数组 a a a 的前 i i i 个数,和为 j j j 的方案数。
状态转移
d p [ i ] [ j ] = ∑ d p [ i − 1 ] [ k ] , ( 1 ≤ j − k ≤ m ) dp[i][j]=\sum\limits dp[i-1][k],(1\leq j-k\leq m) dp[i][j]=∑dp[i−1][k],(1≤j−k≤m)
状态转移只用到了第 i − 1 i-1 i−1 的状态,故可以用两个数组滚动即可。文章来源:https://www.toymoban.com/news/detail-706242.html
时间复杂度: O ( n m k ) O(nmk) O(nmk)文章来源地址https://www.toymoban.com/news/detail-706242.html
代码
#include <bits/stdc++.h>
using namespace std;
const int MOD = 998244353;
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n, m, k;
cin >> n >> m >> k;
// dp[i][j] 表示前 i 个数,和为 j 的方案数
// dp[i][j] = dp[i - 1][k], k < j
vector<int> dp(k + 1);
vector<int> ndp(k + 1);
dp[0] = 1;
for (int i = 1; i <= n; ++i) {
for (int j = i; j <= min(k, i * m); ++j) {
ndp[j] = 0;
// 最低是 i-1, 但是当前最多为 m ,所以 j-m
for (int ch = 1; ch <= m && j - ch >= i - 1; ++ch) {
ndp[j] += dp[j - ch];
if (ndp[j] >= MOD) ndp[j] -= MOD;
}
}
swap(dp, ndp);
}
int ans = 0;
for (int j = n; j <= min(n * m, k); ++j) {
ans += dp[j];
if (ans >= MOD) ans -= MOD;
}
cout << ans << "\n";
return 0;
}
到了这里,关于【每日一题】ABC248C - Dice Sum | 动态规划 |简单的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!