【C++二分查找 贪心】1648. 销售价值减少的颜色球

CSDN 2024-09-13 14:05:01 阅读 78

本文涉及的基础知识点

C++二分查找

贪心

LeetCode1648. 销售价值减少的颜色球

你有一些球的库存 inventory ,里面包含着不同颜色的球。一个顾客想要 任意颜色 总数为 orders 的球。

这位顾客有一种特殊的方式衡量球的价值:每个球的价值是目前剩下的 同色球 的数目。比方说还剩下 6 个黄球,那么顾客买第一个黄球的时候该黄球的价值为 6 。这笔交易以后,只剩下 5 个黄球了,所以下一个黄球的价值为 5 (也就是球的价值随着顾客购买同色球是递减的)

给你整数数组 inventory ,其中 inventory[i] 表示第 i 种颜色球一开始的数目。同时给你整数 orders ,表示顾客总共想买的球数目。你可以按照 任意顺序 卖球。

请你返回卖了 orders 个球以后 最大 总价值之和。由于答案可能会很大,请你返回答案对 109 + 7 取余数 的结果。

示例 1:

在这里插入图片描述

输入:inventory = [2,5], orders = 4

输出:14

解释:卖 1 个第一种颜色的球(价值为 2 ),卖 3 个第二种颜色的球(价值为 5 + 4 + 3)。

最大总和为 2 + 5 + 4 + 3 = 14 。

示例 2:

输入:inventory = [3,5], orders = 6

输出:19

解释:卖 2 个第一种颜色的球(价值为 3 + 2),卖 4 个第二种颜色的球(价值为 5 + 4 + 3 + 2)。

最大总和为 3 + 2 + 5 + 4 + 3 + 2 = 19 。

示例 3:

输入:inventory = [2,8,4,10,6], orders = 20

输出:110

示例 4:

输入:inventory = [1000000000], orders = 1000000000

输出:21

解释:卖 1000000000 次第一种颜色的球,总价值为 500000000500000000 。 500000000500000000 对 109 + 7 取余为 21 。

提示:

1 <= inventory.length <= 105

1 <= inventory[i] <= 109

1 <= orders <= min(sum(inventory[i]), 109)

二分查找+贪心

令最后一个球的价值为x,则不存在球大于x,否则与此球交换。

Cnt(x):价值大于x的球数量。

Check 函数: Cnt(x) >= order

二分类型:查找尾端

Check函数的参数:[1,1e9]

返回值:cnt1 = order - Cnt(ret+1) 价值大于ret的价值和+cnt1*ret。

代码

核心代码

<code>template<class INDEX_TYPE>

class CBinarySearch

{ -- -->

public:

CBinarySearch(INDEX_TYPE iMinIndex, INDEX_TYPE iMaxIndex):m_iMin(iMinIndex),m_iMax(iMaxIndex) { }

template<class _Pr>

INDEX_TYPE FindFrist( _Pr pr)

{

auto left = m_iMin - 1;

auto rightInclue = m_iMax;

while (rightInclue - left > 1)

{

const auto mid = left + (rightInclue - left) / 2;

if (pr(mid))

{

rightInclue = mid;

}

else

{

left = mid;

}

}

return rightInclue;

}

template<class _Pr>

INDEX_TYPE FindEnd( _Pr pr)

{

int leftInclude = m_iMin;

int right = m_iMax + 1;

while (right - leftInclude > 1)

{

const auto mid = leftInclude + (right - leftInclude) / 2;

if (pr(mid))

{

leftInclude = mid;

}

else

{

right = mid;

}

}

return leftInclude;

}

protected:

const INDEX_TYPE m_iMin, m_iMax;

};

class Solution {

public:

int maxProfit(vector<int>& inventory, int orders) {

auto Check = [&](int mid) {

long long cnt = 0;

for (const auto& n : inventory) {

cnt += max(0, n - mid+1);

}

return cnt >= orders;

};

auto ret = CBinarySearch<int>(1, 1e9).FindEnd(Check);

long long llPro = 0;

for (const long long n : inventory) {

if (n > ret) {

orders -= (n - ret);

llPro += (n + ret + 1) * (n - ret) / 2;

}

}

llPro += ret * (long long)orders;

return llPro %((int)1e9 + 7);

}

};

单元测试

vector<int> inventory;

int orders;

TEST_METHOD(TestMethod11)

{

inventory = { 2,5 }, orders = 4;

auto res = Solution().maxProfit(inventory, orders);

AssertEx(14, res);

}

TEST_METHOD(TestMethod12)

{

inventory = { 3,5 }, orders = 6;

auto res = Solution().maxProfit(inventory, orders);

AssertEx(19, res);

}

TEST_METHOD(TestMethod13)

{

inventory = { 2,8,4,10,6 }, orders = 20;

auto res = Solution().maxProfit(inventory, orders);

AssertEx(110, res);

}

TEST_METHOD(TestMethod14)

{

inventory = { 1000000000 }, orders = 1000000000;

auto res = Solution().maxProfit(inventory, orders);

AssertEx(21, res);

}

扩展阅读

我想对大家说的话
工作中遇到的问题,可以按类别查阅鄙人的算法文章,请点击《算法与数据汇总》。
学习算法:按章节学习《喜缺全书算法册》,大量的题目和测试用例,打包下载。重视操作
有效学习:明确的目标 及时的反馈 拉伸区(难度合适) 专注
闻缺陷则喜(喜缺)是一个美好的愿望,早发现问题,早修改问题,给老板节约钱。
子墨子言之:事无终始,无务多业。也就是我们常说的专业的人做专业的事。
如果程序是一条龙,那算法就是他的是睛
失败+反思=成功 成功+反思=成功

视频课程

先学简单的课程,请移步CSDN学院,听白银讲师(也就是鄙人)的讲解。

https://edu.csdn.net/course/detail/38771

如何你想快速形成战斗了,为老板分忧,请学习C#入职培训、C++入职培训等课程

https://edu.csdn.net/lecturer/6176

测试环境

操作系统:win7 开发环境: VS2019 C++17

或者 操作系统:win10 开发环境: VS2022 C++17

如无特殊说明,本算法用**C++**实现。



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。