销售价值减少的颜色球
你有一些球的库存 inventory ,里面包含着不同颜色的球。一个顾客想要 任意颜色 总数为 orders 的球。
这位顾客有一种特殊的方式衡量球的价值:每个球的价值是目前剩下的 同色球 的数目。比方说还剩下 6 个黄球,那么顾客买第一个黄球的时候该黄球的价值为 6 。这笔交易以后,只剩下 5 个黄球了,所以下一个黄球的价值为 5 (也就是球的价值随着顾客购买同色球是递减的)
给你整数数组 inventory ,其中 inventory[i] 表示第 i 种颜色球一开始的数目。同时给你整数 orders ,表示顾客总共想买的球数目。你可以按照 任意顺序 卖球。
请你返回卖了 orders 个球以后 最大 总价值之和。由于答案可能会很大,请你返回答案对 109 + 7 取余数 的结果。
- 复杂二分查找:需要对二分查找的本质深入理解(待学习)
- 设x为最终价格阈值,【0,x】可以卖出不少于order个球,(x,max(同类球数)】卖不出orders个球。(注意开闭区间)
- 举例:inventory[5,2,3],orers=5。 使用二分寻找最后一次求和的个数值,然后超过的部分使用求和公式来计算(比如5、3),一样的部分就直接乘法计算(比如2)
/*
* Copyright (c) Huawei Technologies Co., Ltd. 2023-2023. All rights reserved.
*/
package com.huawei.prac;
import java.util.Arrays;
class SolutionSt {
public static void main(String[] args) {
int[] inventory = {2, 5};
int orders = 4;
int[] inventory1 = {497978859, 167261111, 483575207, 591815159};
int orders1 = 836556809;
int[] inventory2 = {1000000000};
int orders2 = 1000000000;
System.out.println(maxProfit(inventory, orders));
System.out.println(maxProfit(inventory1, orders1));
System.out.println(maxProfit(inventory2, orders2));
}
/**
* 1648. 销售价值减少的颜色球[复杂二分查找+数理逻辑]
*
* @param inventory 颜色球数组:第I个颜色球的数量
* @param orders 顾客总共想买的球数目
* @return 最大销售价总和
*/
public static int maxProfit(int[] inventory, int orders) {
long maxMoney = 0;
long mod = (long) (Math.pow(10, 9) + 7);
long finalNum = getFinalNum(inventory, orders);
for (int num : inventory) {
if (num > finalNum) {
maxMoney += ((finalNum + num + 1) * (num - finalNum)) >> 1;
orders -= (num - finalNum);
}
}
maxMoney += finalNum * orders;
return (int) (maxMoney % mod);
}
private static long getFinalNum(int[] inventory, int orders) {
Arrays.sort(inventory);
int left = 0;
int right = inventory[inventory.length - 1];
int mid;
while (left < right) {
mid = left + ((right - left) >> 1);
long countMid = countMid(inventory, mid);
if (countMid > orders) {
left = mid + 1;
} else {
right = mid;
}
}
return left;
}
private static long countMid(int[] inventory, int mid) {
long countMid = 0;
for (int num : inventory) {
countMid += Math.max(num - mid, 0);
}
return countMid;
}
}```