洛谷P2422 良好的感觉(Problem J)

原题链接:良好的感觉 - 洛谷

 把过程写在下面代码里了,在代码后面还有样例的演示(有点多,可能会有打错字,不要骂我🙌)

思路:确定以每一个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删除中比较最大值即可。

  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值