【思维题】CodeForce 817D Imbalanced Array

这段时间要沉迷刷题一段时间了,就让CSDN陪我一起吧!

一、题目大意

codeforce的题目还是一如既往的简单明了。题目的大致意思就是给你一个数组,要你求数组所有连续子序列的最大值-最小值之和。

二、题目思路以及AC代码

这看到题目之后,第一反应想出了O(n^2)的解决思路(直接暴力嘛),虽然知道肯定超时,还是尝试性的提交了一下,嗯,不错,过了11个数据。

好,下面就说一般思路。首先题目要求的是所有连续子序列的最大值-最小值之和,我们可以不从子序列的角度去思考,而是从最大最小值的角度去思考,无非就是要求数组中的某一个数作为最大值和最小值,分别在连续子序列中出现的次数,有了这些次数,和数组元素一乘,就得到最终结果了。

那么怎么知道某元素作为最大最小值出现的次数呐?先看最大值的次数,这里要用到单调栈的知识,建立两个数组l,r,其中l[i]表示数组元素a[i]左边最后一个小于a[i]的元素的下标,r[i]表示数组元素a[i]的右边最后一个小于a[i]的元素下标,这样我们要求的最大值的次数,就是(i-l[i]+1)*(r[i]-i+1)了,其中(i-l[i]+1)表示的是可以从l[i]到i中随便找一个元素作为子序列的起始,(r[i]-i+1)表示的是可以从i到r[i]中随便找一个元素作为子序列的终止,可能有同学会发现其中是有问题的,比如我选择i作为我的起始,i作为我的终止,那么这个并不会加到结果上,但是这种情况会在计算最小值次数的时候被抵消。

按照同样的方法再计算最小值的次数,然后我们的结果就是∑ (a[i]*a[i]作为最大值出现次数 - a[i]*a[i]作为最小值出现次数)。

下面给出AC代码:

#include <iostream>
#define MAXN 1000005
using namespace std;

int N;
long long l[MAXN];
long long r[MAXN];
long long a[MAXN];

int main()
{
	cin >> N;

	long long res = 0;
	for (int i = 1; i <= N; i++) {
		cin >> a[i];
	}

	for (int i = 1; i <= N; i++) {
		l[i] = i; r[i] = i;
	}
	for (int i = 2; i <= N; i++) {
		int now = i;
		while (now > 1 && a[i] >= a[now - 1]) 
			now = l[now - 1];
		l[i] = now;
	}
	for (int i = N-1; i >=1; i--) {
		int now = i;
		while (now < N && a[i] >= a[now + 1]) 
			now = r[now + 1];
		r[i] = now;
	}
	for (int i = 1; i <= N; i++) {
		res += (i - l[i] + 1)*(r[i] - i + 1)*a[i];
	}

	for (int i = 1; i <= N; i++) {
		l[i] = r[i] = i;
	}
	for (int i = 2; i <= N; i++) {
		int now = i;
		while (now > 1 && a[i] <= a[now - 1]) 
			now = l[now - 1];
		l[i] = now;
	}
	for (int i = N-1; i >= 1; i--) {
		int now = i;
		while (now < N && a[i] <= a[now + 1]) 
			now = r[now + 1];
		r[i] = now;
	}
	for (int i = 1; i <= N; i++) {
		res -= (i - l[i] + 1)*(r[i] - i + 1)*a[i];
	}

	cout << res << endl;

	return 0;
}

如果有问题,欢迎大家指正!!!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值