LeetCode 6077. 巫师的总力量和

一、题目

1、题目描述

  作为国王的统治者,你有一支巫师军队听你指挥。给你一个下标从 0 开始的整数数组 strength,其中 strength[i]表示第 i位巫师的力量值。对于连续的一组巫师(也就是这些巫师的力量值是 strength的 子数组),总力量 定义为以下两个值的 乘积 :
  巫师中 最弱 的能力值。
  组中所有巫师的个人力量值 之和
  请你返回 所有巫师组的总力量之和。由于答案可能很大,请将答案对 1 0 9 + 7 10^9+7 109+7 取余 后返回。
  样例输入: strength = [1,3,1,2]
  样例输出: 44

2、基础框架

  • C++ 版本给出的基础框架代码如下:
class Solution {
public:
    int totalStrength(vector<int>& strength) {
        
    }
};

3、原题链接

LeetCode 6077. 巫师的总力量和

二、解题报告

1、思路分析

   ( 1 ) (1) (1) 恶心!一看到题目,就知道一定又是 1 0 5 10^5 105,所以 O ( n 2 ) O(n^2) O(n2) 是肯定过不了的。
   ( 2 ) (2) (2) 将样例的数据抽象成二维的直方图,数据的值代表高度。

   ( 3 ) (3) (3) 如果枚举任意一块直方图 i i i,以它为最低点,找左边能够到达的最远边界,以及右边能够到达的最远边界,左边界定义为 l i l_i li,右边界定义为 r i r_i ri
在这里插入图片描述

   ( 4 ) (4) (4) 接下来问题就转换成在 [ l i , i ] [l_i, i] [li,i] 找一个下标 j j j,并且在 [ i , r i ] [i, r_i] [i,ri] 找一个下标 k k k,并且求 ∑ o = j k h [ o ] \sum_{o=j}^{k} h[o] o=jkh[o]
   ( 5 ) (5) (5) 于是,对于第 i i i 个直方图,以它为最低点,得到的力量值应该就是 h [ i ] × ∑ j = l i i ∑ k = i r i ∑ o = j k h [ o ] h[i] \times \sum_{j=l_i}^{i} \sum_{k=i}^{r_i}\sum_{o=j}^{k} h[o] h[i]×j=liik=irio=jkh[o]
   ( 6 ) (6) (6) 如果我们知道 h [ i ] h[i] h[i] 的前缀和 s [ i ] s[i] s[i],就可以将第三个循环优化掉,如下: h [ i ] × ∑ j = l i i ∑ k = i r i ( s [ k ] − s [ j − 1 ] ) h[i] \times \sum_{j=l_i}^{i} \sum_{k=i}^{r_i} (s[k] - s[j-1]) h[i]×j=liik=iri(s[k]s[j1])
   ( 7 ) (7) (7) 假设 j j j 为常量,则将最内层的求和进行展开,得到:
= h [ i ] × ∑ j = l i i ( s [ i ] − s [ j − 1 ] ) + . . . + ( s [ r i ] − s [ j − 1 ] ) = h [ i ] × ∑ j = l i i ( s [ i ] + . . . + s [ r i ] ) − ( r i − i + 1 ) s [ j − 1 ] \begin{aligned} &= h[i] \times \sum_{j=l_i}^{i} (s[i] - s[j-1]) + ... + (s[r_i] - s[j-1]) \\ &= h[i] \times \sum_{j=l_i}^{i} (s[i]+...+s[r_i] )- (r_i-i+1) s[j-1]\end{aligned} =h[i]×j=lii(s[i]s[j1])+...+(s[ri]s[j1])=h[i]×j=lii(s[i]+...+s[ri])(rii+1)s[j1]
   ( 8 ) (8) (8) 如果我们知道 s [ i ] s[i] s[i] 的前缀和 s s [ i ] ss[i] ss[i],就可以将上述的求和优化掉,如下: h [ i ] × ∑ j = l i i ( s s [ r i ] − s s [ i − 1 ] ) − ( r i − i + 1 ) s [ j − 1 ] h[i] \times \sum_{j=l_i}^{i} (ss[r_i] - ss[i-1]) - (r_i-i+1) s[j-1] h[i]×j=lii(ss[ri]ss[i1])(rii+1)s[j1]
   ( 9 ) (9) (9) 如果这样计算,枚举 i i i j j j,最坏时间复杂度是 O ( n 2 ) O(n^2) O(n2),于是,我们而已考虑假设 k k k 作为常量的情况,得到如下等式:
= h [ i ] × ∑ j = l i i ∑ k = i r i ( s [ k ] − s [ j − 1 ] ) = h [ i ] × ∑ k = i r i ( s [ k ] − s [ l i − 1 ] ) + . . . + ( s [ k ] − s [ i − 1 ] ) = h [ i ] × ∑ k = i r i ( i − l i + 1 ) s [ k ] − ( s [ l i − 1 ] + . . . + s [ i − 1 ] ) = h [ i ] × ∑ k = i r i ( i − l i + 1 ) s [ k ] − ( s s [ i − 1 ] − s s [ l i − 2 ] ) \begin{aligned} &= h[i] \times \sum_{j=l_i}^{i} \sum_{k=i}^{r_i} (s[k] - s[j-1]) \\ &= h[i] \times \sum_{k=i}^{r_i} (s[k] - s[l_i-1]) + ... + (s[k] - s[i-1]) \\ &= h[i] \times \sum_{k=i}^{r_i} (i - l_i+1) s[k] - (s[l_i-1]+...+s[i-1] ) \\ &= h[i] \times \sum_{k=i}^{r_i} (i - l_i+1) s[k] - (ss[i-1] - ss[l_i-2] )\end{aligned} =h[i]×j=liik=iri(s[k]s[j1])=h[i]×k=iri(s[k]s[li1])+...+(s[k]s[i1])=h[i]×k=iri(ili+1)s[k](s[li1]+...+s[i1])=h[i]×k=iri(ili+1)s[k](ss[i1]ss[li2])

2、时间复杂度

   最坏时间复杂度 O ( n 2 ) O(n^2) O(n2),但是还是很难卡数据的。

3、代码详解

class Solution {
    #define ll long long
    #define maxn 100010
    #define mod 1000000007

    ll h[maxn];
    ll s[maxn], ss[maxn];
    int l[maxn], r[maxn];

    ll getss(int idx) {
        return idx == -1 ? 0 : ss[idx];
    }

public:
    int totalStrength(vector<int>& strength) {
        int i, j, k;
        int n = strength.size();
        ll ret = 0;
        
        h[0] = h[n+1] = -1;
        for(i = 0; i < n; ++i) {
            h[i+1] = strength[i];
            l[i+1] = r[i+1] = i+1;
        }
        s[0] = ss[0] = 0;
        for(i = 1; i <= n; ++i) {
            s[i] = s[i-1] + h[i];
            ss[i] = ss[i-1] + s[i];
        }

        for(i = 1; i <= n; ++i) {
            while(h[ l[i]-1 ] > h[i] ) {
                l[i] = l[ l[i]-1 ];
            }
        }
        for(i = n; i >= 1; --i) {
            while(h[ r[i]+1 ] >= h[i]  ) {
                r[i] = r[ r[i]+1 ];
            }
        }
        
        for(i = 1; i <= n; ++i) {
            ll hv = h[i];
            ll ans = 0;
            ll L = l[i];
            ll R = r[i];
            if(i-L < R-i) {
                for(j = L; j <= i; ++j) {
                    ans += (ss[R] - ss[i-1]) - s[j-1]*(R - i + 1);
                    if(ans >= mod) {
                        ans %= mod;
                    }
                }
            }else {
                for(k = i; k <= R; ++k) {
                    ans += s[k] * (i - L + 1) - (ss[i-1] - getss(L-2));
                    if(ans >= mod) {
                        ans %= mod;
                    }
                }
            }

            ret = (ret + ans * hv % mod) % mod;
        }
        return ret;
    }
};

三、本题小知识

  比赛时候,推导非常重要,思路一定要清晰。


四、加群须知

  相信看我文章的大多数都是「 大学生 」,能上大学的都是「 精英 」,那么我们自然要「 精益求精 」,如果你还是「 大一 」,那么太好了,你拥有大把时间,当然你可以选择「 刷剧 」,然而,「 学好算法 」,三年后的你自然「 不能同日而语 」
  那么这里,我整理了「 几十个基础算法 」 的分类,点击开启:

🌌《算法入门指引》🌌

  如果链接被屏蔽,或者有权限问题,可以私聊作者解决。

  大致题集一览:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述



在这里插入图片描述


  为了让这件事情变得有趣,以及「 照顾初学者 」,目前题目只开放最简单的算法 「 枚举系列 」 (包括:线性枚举、双指针、前缀和、二分枚举、三分枚举),当有 一半成员刷完 「 枚举系列 」 的所有题以后,会开放下个章节,等这套题全部刷完,你还在群里,那么你就会成为「 夜深人静写算法 」专家团 的一员。
  不要小看这个专家团,三年之后,你将会是别人 望尘莫及 的存在。如果要加入,可以联系我,考虑到大家都是学生, 没有「 主要经济来源 」,在你成为神的路上,「 不会索取任何 」
  🔥联系作者,或者扫作者主页二维码加群,加入刷题行列吧🔥


🔥让天下没有难学的算法🔥

C语言免费动漫教程,和我一起打卡!
🌞《光天化日学C语言》🌞

让你养成九天持续刷题的习惯
🔥《九日集训》🔥

入门级C语言真题汇总
🧡《C语言入门100例》🧡

组团学习,抱团生长
🌌《算法零基础100讲》🌌

几张动图学会一种数据结构
🌳《画解数据结构》🌳

竞赛选手金典图文教程
💜《夜深人静写算法》💜
  • 11
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

英雄哪里出来

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值