题解:洛谷 B4051 小杨的武器

【题目来源】

洛谷:B4051 [GESP202409 五级] 小杨的武器 - 洛谷

【题目描述】

小杨有\(n\)种不同的武器,他对第 \(i\) 种武器的初始熟练度为\(c_i\)

小杨会依次参加\(m\) 场战斗,每场战斗小杨只能且必须选择一种武器使用。假设小杨使用了第\(i\)种武器参加了第\(j\)场战斗,战斗前该武器的熟练度为\(c'_i\),则战斗后小杨对该武器的熟练度会变为\(c'_i+a_j\)。需要注意的是\(a_j\)可能是正数、0或负数,这意味着小杨参加战斗后对武器的熟练度可能会提高,也可能会不变,还有可能降低。

小杨想请你编写程序帮助他计算出如何选择武器才能使得\(m\) 场战斗后,自已对\(n\)种武器的熟练度的最大值尽可能大。

【输入】

第一行包含两个正整数\(n\)\(m\),含义如题面所示。

第二行包含\(n\)个正整数\(c_1,c_2,\dots,c_n\),代表小杨对武器的初始熟练度。

第三行包含\(m\)个正整数\(a_,a_2,\dots, a_m\),代表每场战斗后武器熟练度的变化值。

【输出】

输出一个整数,代表\(m\) 场场战斗后小杨对\(n\)种武器的熟练度的最大值最大是多少。

【输入样例】

2 2
9 9
1 -1

【输出样例】

10

【核心思想】

  1. 问题分析:给定 \(n\) 种武器的初始熟练度 \(c_i\)\(m\) 场战斗的熟练度变化值 \(a_j\)。每场战斗必须选择一种武器,该武器熟练度增加 \(a_j\)。求 \(m\) 场战斗后所有武器熟练度最大值的最大可能值。这是一个贪心策略问题,核心在于分析如何将每场战斗的增益分配给最优武器。

  2. 算法选择

    • 贪心分配:将最大初始熟练度的武器作为"主武器",所有正增益都分配给该武器;负增益分配给非主武器(或当只有 \(1\) 种武器时不得不承受)
    • 最大值维护:只需追踪当前最大熟练度,无需维护所有武器状态
  3. 关键步骤

    • 读入数据:读取 \(n, m\),初始熟练度 \(c[1..n]\),战斗增益 \(a[1..m]\)
    • 确定主武器\(mx \leftarrow \max_{i=1}^{n} c_i\),即初始最大熟练度
    • 处理每场战斗\(j\)\(1\)\(m\)):
      • \(n = 1\)(只有一把武器):\(mx \leftarrow mx + a_j\)(所有变化都作用于该武器)
      • 否则若 \(a_j > 0\)\(mx \leftarrow mx + a_j\)(正增益分配给当前最强武器,使其更强)
      • 否则:不操作(负增益分配给非主武器,不影响最大值)
    • 输出结果\(mx\)
  4. 时间/空间复杂度

    • 时间复杂度:\(O(n + m)\),遍历初始熟练度和战斗增益各一次
    • 空间复杂度:\(O(n + m)\),存储输入数组
  5. 贪心策略的核心思想

    • 集中优势资源:所有正增益都集中分配给当前熟练度最高的武器,使其始终保持最大,这是最大化最终最大值的贪心策略
    • 负增益的规避:当有多种武器时,负增益可以分配给非主武器,不影响最大熟练度。只有一把武器时无法规避,必须承受
    • 最优子结构:每场战斗的最优决策只依赖于当前最大熟练度,与具体是哪把武器无关,因此只需维护最大值
    • 单调性保证:正增益使最大值增加,负增益不减少最大值(当 \(n \geq 2\) 时),因此最终最大值具有单调不减性
    • 适用于资源集中分配、最大化极值类贪心问题

【算法标签】

普及- #贪心

【代码详解】

#include <bits/stdc++.h>
using namespace std;
const int N = 100010;  // 定义数组大小常量
int a[N], c[N];  // 定义两个数组,一个存储每场战斗的增益值,一个存储初始熟练度
int main()
{
	int n, m;  // 定义变量n和m,分别表示武器种类数和战斗次数
	cin >> n >> m;  // 输入n和m
	int mx = -10000;  // 初始化最大熟练度为一个较小的值
	for (int i=1; i<=n; i++) {  // 循环输入每种武器的初始熟练度
		cin >> c[i];
		mx = max(mx, c[i]);  // 更新当前最大熟练度
	}

	for (int i=1; i<=m; i++) {  // 循环输入每场战斗的增益值
		cin >> a[i];
	}

	for (int i=1; i<=m; i++) {  // 根据战斗增益更新最大熟练度
		if (n==1 || a[i]>0) {  // 如果只有一种武器或者当前战斗增益为正
			mx += a[i];  // 增加最大熟练度
		}
	}
	cout << mx << endl;  // 输出最终的最大熟练度
	return 0;
}

【运行结果】

2 2
9 9
1 -1
10
posted @ 2026-07-17 14:44  团爸讲算法  阅读(7)  评论(0)    收藏  举报