【每日一题】ABC248C - Dice Sum | 动态规划 |简单

文章介绍了如何使用动态规划解决一个关于构造整数数组的问题,满足特定的和限制。通过定义状态转移方程和计算不同和的方案数,最后给出时间复杂度并附有C++代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目内容

原题链接

构造一个长度为 n n n 的整数数组 a a a ,满足如下两个条件:

  • 1 ≤ a i ≤ m 1\leq a_i\leq m 1aim
  • ∑ a i ≤ k \sum a_i\leq k aik

问可以构造出多少种不同的数组 a a a

数据范围

  • 1 ≤ n , m ≤ 50 1\leq n,m\leq 50 1n,m50
  • n ≤ k ≤ n × m n\leq k\leq n\times m nkn×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[i1][k],(1jkm)

状态转移只用到了第 i − 1 i-1 i1 的状态,故可以用两个数组滚动即可。

时间复杂度: O ( n m k ) O(nmk) O(nmk)

代码

#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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值