LeetCode每日一题2025-10-11-LC3186-施咒的最大伤害
3186-施咒的最大伤害
思路
题目大意是:选出一个子集,这个子集需要满足一个要求:子集中元素相互之间的差值不能是1和2,目标求最大子集和
-
直接考虑一个元素应不应该被选上既要考虑比它小的,又要考虑比它大的,比较麻烦,我们直接从小往大考虑,加入一个数的时候就只用考虑比它小的数就可以了,所以我们先把数组排个序
-
接着我们考虑每一个元素,对于元素\(a_i\),如果\(a_{i - 1} = a_i\),那么\(a_i\)肯定跟在\(a_{i - 1}\)的后面才能保证此时是在选上\(a_{i}\)的情况下的最优解
-
如果\(a_{i - 1} \neq a_{i}\),此时我们在一个合法范围内\((a_i - a_j \geq 3)\)时找一个最大值就好,因为我们已经提前排过序了,所以此时可用用二分查找, 找最大值就理所当然地维护一个前缀最大值就好了
那么这个题目我们就维护两个数组就好了
\(premax[i]\) : 前\(i\)个元素取值的最大值
\(dp[i]\) : 前\(i\)个元素,选上元素\(i\)时的最大值
\[premax[i] =
\begin{cases}
power[0] &i = 0\\
max(premax[i - 1], \space dp[i]) &i > 0
\end{cases}
\]
\[dp[i] = \begin{cases}
power[0] &i = 0\\
dp[i - 1] + power[i] &power[i] = power[i - 1]\\
Max_{j = 0}^{i - 1}dp[j] + power[i] &power[i] \neq power[i - 1]
\end{cases}
\]
代码
using lli = long long;
class Solution {
public:
lli maximumTotalDamage(std::vector<int>& power)
{
int n = power.size();
std::vector<lli> premax(n, 0);
std::vector<lli> dp(n, 0);
std::sort(power.begin(), power.end());
dp[0] = power[0];
premax[0] = dp[0];
for (int i = 1; i < n; i++)
{
if (power[i] == power[i - 1])
{
dp[i] = dp[i - 1] + power[i];
}
else
{
int l = -1, r = i;
while(l + 1 < r)
{
int mid = (l + r) >> 1;
if (power[i] - power[mid] >= 3)
{
l = mid;
}
else
{
r = mid;
}
}
if (l == -1)
{
dp[i] = power[i];
}
else
{
dp[i] = premax[l] + power[i];
}
}
premax[i] = std::max(premax[i - 1], dp[i]);
}
lli ans = 0;
for (int i = 0; i < n; i++) ans = std::max(ans, dp[i]);
return ans;
}
};

浙公网安备 33010602011771号