字节员工吐槽:年薪100万,依然被媳妇挂在网上,被嘲扶贫。。
刚看到个贴子,字节的员工吐槽自己年入百万,结果还被枕边人拿去网上嘲笑“扶贫”。
网友有说“人中龙凤也不行”“赚钱没用”,也有人觉得“有钱就够了别矫情”。但我觉得,这事不是钱多钱少的问题,而是价值观错位。
一个拼命赚钱的打工人,却被最亲近的人看不起,这种精神落差才最伤人。
说到底,互联网人不是“扶贫”,是努力换生活。挣再多也想被理解,而不是被贬低。别用别人的职业来定义尊严,每个人都在自己的位置上辛苦生活。
尊重劳动,才是最该普及的底层逻辑。【备注:文末可领最新资料】
算法题:巫师的总力量和
有一排巫师,每个巫师有个“力量值”a[i]。任意连续一段的“队伍总力量”= 这段里最小值 × 这段元素和。题目要所有子数组的“队伍总力量”之和,结果很大取模 1e9+7。
直接枚举子数组会超时。换个角度:固定某个位置 i 当成它所在子数组的最小值,把它对答案的贡献一次算清。 关键是找出所有把 a[i] 当最小值的子数组范围,这通常用单调栈做“左右边界”:
左边界 L:离 i 最近、严格小于 a[i] 的位置(没有就设为 -1)。 右边界 R:离 i 最近、小于等于 a[i] 的位置(没有就设为 n)。 用“左<、右≤”这一套,比“都<”更容易去重。
这样,i 左边可选的起点个数是 left = i - L,右边可选的终点个数是 right = R - i。但我们还需要这些子数组的区间和。直接累加仍然会慢,于是再上一个经典招:前缀和的前缀和(双前缀)。
定义:
pre[k] = a[0] + … + a[k-1](长度为 n+1)pp[k] = pre[0] + … + pre[k-1](长度为 n+1)
有了它们,可以 O(1) 求“若干区间和的总和”。最终结论(推导略):
对每个 i 的贡献:
sumRight = pp[R+1] - pp[i+1] // 相当于聚合了所有以右端点落在 [i, R-1] 的区间和
sumLeft = pp[i+1] - pp[L+1] // 相当于聚合了所有以左端点落在 [L+1, i] 的区间和
贡献 = a[i] * ( sumRight * left - sumLeft * right )
全程取模,注意负数要加模。
复杂度与坑
单调栈两次扫:O(n)。 预处理双前缀:O(n)。 贡献求和:O(n)。 总体 O(n),内存 O(n)。 坑点: 1)右边界用“≤”,左边界用“<”,否则重复或漏计。 2)中间乘法、减法都要上 long 与取模防溢出与负数。
Java 实现
import java.util.*;
publicclassSolution{
staticfinallong MOD = 1_000_000_007L;
publicinttotalStrength(int[] a){
int n = a.length;
// 1) 前缀和 pre,二级前缀 pp
long[] pre = newlong[n + 1];
for (int i = 0; i < n; i++) pre[i + 1] = (pre[i] + a[i]) % MOD;
long[] pp = newlong[n + 1];
for (int i = 0; i < n; i++) pp[i + 1] = (pp[i] + pre[i + 1]) % MOD;
// 2) 左边界:prevLess(严格小于)
int[] L = newint[n];
Deque<Integer> st = new ArrayDeque<>();
for (int i = 0; i < n; i++) {
while (!st.isEmpty() && a[st.peek()] >= a[i]) st.pop(); // 为了右边用≤,这边配套成 < :这里要“>=”弹出
L[i] = st.isEmpty() ? -1 : st.peek();
st.push(i);
}
// 3) 右边界:nextLessEqual(小于等于)
int[] R = newint[n];
st.clear();
for (int i = n - 1; i >= 0; i--) {
while (!st.isEmpty() && a[st.peek()] > a[i]) st.pop(); // 右边要“≤”保留相等,因此这里弹出“>”
R[i] = st.isEmpty() ? n : st.peek();
st.push(i);
}
// 4) 累加贡献
long ans = 0;
for (int i = 0; i < n; i++) {
int left = i - L[i];
int right = R[i] - i;
long sumRight = (pp[R[i] + 1] - pp[i + 1]) % MOD; // pp索引+1别写错
long sumLeft = (pp[i + 1] - pp[L[i] + 1]) % MOD;
if (sumRight < 0) sumRight += MOD;
if (sumLeft < 0) sumLeft += MOD;
long contrib = ( (sumRight * left) % MOD - (sumLeft * right) % MOD ) % MOD;
if (contrib < 0) contrib += MOD;
ans = (ans + contrib * a[i]) % MOD;
}
return (int) ans;
}
}
这题的“味儿”就是:栈定最小覆盖范围 + 双前缀批量求区间和。别被公式吓到,代码其实很直。
-END-
我为大家打造了一份RPA教程,完全免费:songshuhezi.com/rpa.html