蓝桥云客 2022

02022 - 蓝桥云课

2022

问题描述
---------
将2022拆分成10个互不相同的正整数之和,总共有多少种拆分方法?
注意交换顺序视为同一种方法,例如2022 = 1000 + 1022 和 2022 = 1022 + 1000 就视为同一种方法。

答案提交
---------
这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。

运行限制
---------
- 最大运行时间:1s
- 最大运行内存:512M

总通过次数:4542 | 总提交次数:5214 | 通过率:87.1%

难度:中等 标签:2022,国赛,背包问题

版权声明
---------

思路:
背包问题

为什么需要三维?

问题的状态由三个关键因素决定:

  1. 可选数的范围i):决定了当前能选哪些数。

  2. 需要选多少个数j):目标是要选恰好 10 个数。

  3. 这些数的和k):目标是要让和为 2022

这三个因素共同唯一确定一个子问题。通过记录这三个维度的结果,可以避免重复计算相同的子问题。

2. 为什么需要这三个参数?

(1) i 的必要性
  • 限制可选范围:例如,当 i=100 时,只能使用 1~100 的数,而不能使用更大的数(如101)。

  • 避免重复计算:如果不包含 i,当处理到不同的 i 时,可能重复计算相同的 j 和 k,但实际上可选数的范围不同,导致方案数不同。

(2) j 和 k 的必要性
  • 明确目标条件:题目要求选恰好 10 个数且和为 2022,因此需要跟踪还需选多少个数 (j) 和还需的和 (k)。

记忆化搜索:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll; 
// 记忆化数组:memo[i][j][k]表示前i个数中选j个数,和为k的方案數
ll memo[2022 + 1][10 + 1][2022 + 1];

ll dfs(ll i, ll j, ll k) 
{
    // 边界条件处理
    if (j < 0 || k < 0) 
	return 0;          // 非法状态
    if (j == 0 && k == 0) 
	return 1;  // 恰好选够且和为0(合法方案)
    if (i == 0) 
	return 0;  // 没有数可选但未满足条件
    if (memo[i][j][k] != -1) 
	return memo[i][j][k];
    
    ll res = 0;
    
    res = dfs(i - 1, j, k); // 不选第i个数的情况
    
    // 选第i个数的情况(需满足k >= i且j至少选1個)
    if (k >= i && j >= 1) 
	{
        res = dfs(i - 1, j, k) + dfs(i - 1, j - 1, k - i);
    }
    return memo[i][j][k] = res;
}

int main() 
{
    memset(memo, -1, sizeof(memo));
    cout << dfs(2022, 10, 2022);
    return 0;
}

dp:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll f[2023][11][2023]; 
int main()
{
    for (ll i = 0; i <= 2022; i++)  //因为体积为0,物品为0的所有情况都只有一种选择,即什么都不选
    f[i][0][0] = 1;
    
    for (ll i= 1; i <= 2022; i++)  //枚举所有物品
    {
        for (ll j = 1; j <= 10; j++)   //选了几个物品
        {
            for (ll k = 1; k <= 2022; k++)  //枚举体积
            {
             	   if (k >= i && j >= 1)  //选第i个物品
                   f[i][j][k] += f[i-1][j - 1][k - i] + f[i-1][j][k];
                   else
                   f[i][j][k] = f[i-1][j][k];  //不选第i个物品
            }
        }
    }
    cout << f[2022][10][2022];
    return 0;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值