力扣每日一题(难的我也不会)2681. 英雄的力量(2023.8.1)

文章讨论了一种计算英雄力量的方法,通过给定整数数组,求所有可能英雄子序列的最大值的平方与最小值的乘积之和,利用排序和前缀和数组优化求解,最终结果对10^9+7取余。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

给你一个下标从 0 开始的整数数组 nums ,它表示英雄的能力值。如果我们选出一部分英雄,这组英雄的 力量 定义为:

  • i0 ,i1 ,... ik 表示这组英雄在数组中的下标。那么这组英雄的力量为 max(nums[i0],nums[i1] ... nums[ik])2 * min(nums[i0],nums[i1] ... nums[ik]) 。

请你返回所有可能的 非空 英雄组的 力量 之和。由于答案可能非常大,请你将结果对 109 + 7 取余。

题意就是求所有子序列的最大值的平方再乘以最小值,因此与顺序无关,先进行排序。

举例数组:[1 ,2, 3,4]

此题应该想到每个值的贡献度(枚举每个数作为最大值),具体思路如下:

从大数开始比较好想(我是这么想的)

举例4,作为最大值的情况有以下几种

4
1 4
2 4
3 4
1 2 4
1 3 4
2 3 4
1 2 3 4

换个顺序看

4
3 4
2 4
2 3 4
1 4
1 2 4
1 3 4
1 2 3 4

题中所述,只需要求每个子序列的最大值和最小值即可

那么有

ans(4) = 4 * 4 * 4 + 4 * 4 * 3 + 4 * 4 * 2 * 2 + 4 * 4 * 1 * 4

简化

ans(4) = 4 * 4 * (4 + 3 + 2 * 2 + 1 * 4)

直接猜下公式

对n来说
An = n ^2 * (n + (n - 1) * 2 ^ 0 + (n - 2) * 2 ^ 1 + (n - 3) * 2 ^ 2 + (n - 4) * 2 ^ 3 ...)
式中 n 均为nums[n]

哎,猜对了

之后直接上代码提交

    public int sumOfPower(int[] nums) {
        int n = nums.length;
        long res = 0;
        int mod = (int) (1e9 + 7);
        Arrays.sort(nums);
        for (int i = n - 1; i >= 0; i--) {
            long n2 = (((long)nums[i] % mod) * ((long)nums[i] % mod)) % mod;
            long sum = nums[i];
            for (int j = i - 1, pow = 0; j >= 0; j--, pow++) {
                sum += ((nums[j] % mod) * (Math.pow(2, pow) % mod)) % mod;
            }
            res += ((n2 % mod) * (sum % mod)) % mod;
        }
        res %= mod;
        return (int) (res);
    }

超时,发现数据范围过大,O2必然不能过

通过规律发现(自己发现的规律,大佬的那个规律更简单)

A1 = (nums[1])
A2 = (nums[2] + nums[1])
A3 = (nums[3] + nums[2] + 2^1 * nums[1]) = nums[3] + nums[2] + (2 * A2 - nums[2])
A4 = (nums[4] + nums[3] + 2^1 * nums[2] + 2^2 * nums[1]) = nums[4] + nums[3] + (2 * A3 - nums[3])

通过一个前缀数组存储

代码如下

    public int sumOfPower(int[] nums) {
        int mod = (int) (1e9 + 7);
        int n = nums.length;
        if (n == 1) return (int) (((((long)nums[0]  * nums[0]) % mod) * nums[0]) % mod);
        long res = 0;
        Arrays.sort(nums);
        long[] prev = new long[n];
        prev[0] = nums[0] % mod;
        prev[1] = (nums[1] % mod + nums[0] % mod) % mod;
        for (int i = 2; i < n; i++) {
            prev[i] = (nums[i] % mod + nums[i - 1] % mod + (2L * (prev[i - 1] - nums[i - 1])) % mod) % mod;
        }
        for (int i = n - 1; i >= 0; i--) {
            long n2 = (((long) nums[i] % mod) * ((long) nums[i] % mod)) % mod;
            long sum = prev[i];
            res += ((n2 % mod) * (sum % mod)) % mod;
        }
        res %= mod;
        return (int) (res);
    }

ok,过了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值