本文涉及的基础知识点

C++二分查找 贪心

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

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

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

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

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

示例 1:

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

输入: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。

代码

核心代码

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);
		}


测试环境

操作系统:win7 开发环境: VS2019 C++17
或者 操作系统:win10 开发环境: VS2022 C++17
如无特殊说明,本算法用**C++**实现。

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