原题链接:良好的感觉 - 洛谷
把过程写在下面代码里了,在代码后面还有样例的演示(有点多,可能会有打错字,不要骂我🙌)
思路:确定以每一个a[i]为最小的区间的舒适值,然后对比这n个舒适值
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<string>
#include<cstring>
#include<list>
#include<queue>
#include<deque>
using namespace std;
typedef long long ll;
const int N = 100005;
deque<ll> q;
ll arr[N], sum[N];//注意数据范围,需要long long
int main() {
int n;
cin >> n;
ll mx = -0x3f3f3f3f3f3f3f3f;//约-pow(2,62)
//这一题还是需要用到前缀和,一次前缀和后可以在O(1)时间算任意区间和
for (int i = 1; i <= n; ++i) {
scanf("%lld", &arr[i]);
sum[i] = arr[i] + sum[i - 1];
}
/*
这题的思路可以去看洛谷p2422,下面提供完全的stl解法。
1.先把前缀和数组用前后两个零圈住(其实原本前后两边就是0了,但要把n++);
2.用单调队列来实现每一个arr[i]的范围,对于每一个arr[i]来说,
在单独队列中,它的前一个就是它的左边界下标,
之后进队列的第一个比它小的数就是它的右边界下标。
可能有些不好想,可以对着样例来看:3 1 6 4 5 2,处理完后变成0 3 1 6 4 5 2 0
首先0入队,接着1入队,这时的队列:{0,1},a[0]就是a[1]的左边界
接着i=2,因为a[2]=1 < a[1]=3,所以a[2]就是a[1]的右边界,
这时可以直接计算以a[1]为最小的区间值的乘积了,拿它和mx比较就可以了
具体看下面代码实现
*/
sum[++n] = 0;
q.push_back(0);
for (int i = 1; i <= n; ++i) {
while (!q.empty() && arr[i] < arr[q.back()]) {
ll tmp = arr[q.back()];
q.pop_back();
ll mul = tmp * (sum[i - 1] - sum[q.back()]);
if (mul > mx) {
mx = mul;
}
}
q.push_back(i);
}
cout << mx;
return 0;
}
sum[i]: 0 3 4 10 14 19 21
arr[i] : 0 3 1 6 4 5 2
索引 : 0 1 2 3 4 5 6
i=0:
arr[i] : 0
索引 : 0
i=1:
arr[i] : 0 3
索引 : 0 1
i=2:
arr[i] : 0 3 1 //此时a[2]=1还未加入队列,只是比较,下面同理
索引 : 0 1 2
031: 1比3小,确定了一个以a[1]为最小的区间:arr[1]到arr[1], 令tmp = arr[q.back()] = 3;
arr[i] : 0 1
索引 : 0 2
此时确定以a[1]为最不舒服一天的总舒适度:tmp * (sum[i - 1] - sum[q.back])=3*(3-0)=9
i=3:
arr[i] : 0 1 6
索引 : 0 2 3
i=4:
arr[i] : 0 1 6 4
索引 : 0 2 3 4
164: 4比6小,确定了一个以a[3]为最小的区间:arr[3]到arr[3], 令tmp = a[q.back()] = 6;
arr[i] : 0 1 4
索引 : 0 2 4
此时确定以a[3]为最不舒服一天的总舒适度:tmp * (sum[i - 1] - sum[q.back]) = 6 * (10 - 4) = 36
i=5:
arr[i] : 0 1 4 5
索引 : 0 2 4 5
i = 6 :
arr[i] : 0 1 4 5 2
索引 : 0 2 4 5 6
452 : 2比5小,确定了一个以a[5]为最小的区间:arr[5]到arr[5], 令tmp = a[q.back()] = 5;
arr[i] : 0 1 4 2
索引 : 0 2 4 6
此时确定以a[5]为最不舒服一天的总舒适度:tmp * (sum[i - 1] - sum[q.back]) = 5 * (19 - 14) = 25
接着:
142 : 2比4小,确定了一个以a[4]为最小的区间:arr[3]到arr[5], 令tmp = a[q.back()] = 4;
arr[i] : 0 1 2
索引 : 0 2 6
此时确定以a[4]为最不舒服一天的总舒适度:tmp * (sum[i - 1] - sum[q.back]) = 4 * (19 - 4) = 60
i=7:
arr[i] : 0 1 2 0
索引 : 0 2 6 0
120 : 0比2小,确定了一个以a[6]为最小的区间:arr[3]到arr[6], 令tmp = a[q.back()] = 2;
arr[i] : 0 1 0
索引 : 0 2 7
此时确定以a[6]为最不舒服一天的总舒适度:tmp * (sum[i - 1] - sum[q.back]) = 2 * (21 - 4) = 34
接着:
010 : 1比0小,确定了一个以a[2]为最小的区间:arr[1]到arr[6], 令tmp = a[q.back()] = 1;
arr[i] : 0 0
索引 : 0 7
此时确定以a[2]为最不舒服一天的总舒适度:tmp * (sum[i - 1] - sum[q.back]) = 1 * (21 - 0) = 21
至此就确定完了以每一个a[i]为最不舒适的区间舒适值了,我们只需要在上面的每一次while删除中比较最大值即可。