巫师的总力量和
总力量定义为以下两个值的 乘积:
巫师中最弱的能力值
组中所有巫师的个人力量值之和
1. 单调栈+前缀和+前缀和
根据单调栈求得每一个值的辖域(当前值为最小值的最长数组范围)
接下来问题就转化成了求在辖域中包含当前值所有子数组的和
求和我们采用前缀和的方式
对于abcde,假设c为当前辖域最小值,则所有子数组和为presum[c/d/e]-presum[a/b/c-1]
presum[c/d/e]要分别列举三次求和,由左边个数决定,presum[a/b/c-1]要列举3次求和,由右边个数决定
为了快速求c/d/e的和,以及a/b/c的和,这里再次使用前缀和
class Solution {
public:
int totalStrength(vector<int>& arr) {
const int mod = 1e9+7;
int n = arr.size();
vector<int> monoStack; //单调栈
vector<int> left(n), right(n);//左右边界
for (int i = 0; i < n; i++) {//从左往右找左边更小值
while (!monoStack.empty() && arr[i] <= arr[monoStack.back()]) {//把更大的值挤出来,相等的视为更大,区间计算的时候不影响
monoStack.pop_back();
}
left[i] = monoStack.empty() ? -1: monoStack.back(); //左边界,左开
monoStack.emplace_back(i);//放入坐标
}
monoStack.clear();
for (int i = n - 1; i >= 0; i--) { //从右往左找右边更小值
while (!monoStack.empty() && arr[i] < arr[monoStack.back()]) {
monoStack.pop_back();
}
right[i] = monoStack.empty() ? n : monoStack.back(); //右边界,右开
monoStack.emplace_back(i);
}
vector<long long> presum(n+1);
vector<long long> sumsum(n+2);
for(int i=0;i<n;i++){
presum[i+1] = presum[i]+arr[i];//前缀和
sumsum[i+2] = (sumsum[i+1]+presum[i+1])%mod;
}
long long res = 0;
for(int i=0;i<n;i++){//遍历每一个数
int r = right[i]-1;//这里是闭区间
int l = left[i]+1;//这里是闭区间
//presum[i]/presum[i+1]....presum[r] - presum[i-1]....presum[l]
//左边个数为i-l+1,右边个数为r-i+1(包含本身)
long long cur = ((sumsum[r+2]-sumsum[i+1])*(i-l+1) - (sumsum[i+1]-sumsum[l])*(r-i+1))%mod;
res = (res+cur*arr[i])%mod;
}
return (res+mod)%mod;
}
};
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· 葡萄城 AI 搜索升级:DeepSeek 加持,客户体验更智能
· 什么是nginx的强缓存和协商缓存
· 一文读懂知识蒸馏
2022-05-19 LeetCode/零钱兑换
2022-05-19 LeetCode/完全平方数