【010·未解】1648. 销售价值减少的颜色球【复杂二分查找+复杂逻辑转化】

销售价值减少的颜色球

你有一些球的库存 inventory ,里面包含着不同颜色的球。一个顾客想要 任意颜色 总数为 orders 的球。
这位顾客有一种特殊的方式衡量球的价值:每个球的价值是目前剩下的 同色球 的数目。比方说还剩下 6 个黄球,那么顾客买第一个黄球的时候该黄球的价值为 6 。这笔交易以后,只剩下 5 个黄球了,所以下一个黄球的价值为 5 (也就是球的价值随着顾客购买同色球是递减的)
给你整数数组 inventory ,其中 inventory[i] 表示第 i 种颜色球一开始的数目。同时给你整数 orders ,表示顾客总共想买的球数目。你可以按照 任意顺序 卖球。
请你返回卖了 orders 个球以后 最大 总价值之和。由于答案可能会很大,请你返回答案对 109 + 7 取余数 的结果。

  1. 复杂二分查找:需要对二分查找的本质深入理解(待学习)
  2. 设x为最终价格阈值,【0,x】可以卖出不少于order个球,(x,max(同类球数)】卖不出orders个球。(注意开闭区间
  3. 举例: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;
    }
}```

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值