一、题目
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、原题链接
二、解题报告
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=li∑ik=i∑rio=j∑kh[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=li∑ik=i∑ri(s[k]−s[j−1])
(
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=li∑i(s[i]−s[j−1])+...+(s[ri]−s[j−1])=h[i]×j=li∑i(s[i]+...+s[ri])−(ri−i+1)s[j−1]
(
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=li∑i(ss[ri]−ss[i−1])−(ri−i+1)s[j−1]
(
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=li∑ik=i∑ri(s[k]−s[j−1])=h[i]×k=i∑ri(s[k]−s[li−1])+...+(s[k]−s[i−1])=h[i]×k=i∑ri(i−li+1)s[k]−(s[li−1]+...+s[i−1])=h[i]×k=i∑ri(i−li+1)s[k]−(ss[i−1]−ss[li−2])
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讲》🌌
几张动图学会一种数据结构 🌳《画解数据结构》🌳
竞赛选手金典图文教程 💜《夜深人静写算法》💜