XTU 1205 Range 2014湖南邀请赛C 单调栈

XTU 1205 Range 2014湖南邀请赛C 单调栈

ACM

题目地址:XTU 1205

题意: 
在一个序列A中,Range(A)=Max(A)-Min(A)+1; 
求一个序列的子序列中所有子序列的Range的和。

分析: 
做了好久。。。多谢Tamara巨巨的指点。 
1 2 3 4 5 
Range(A)=Max(A)-Min(A)+1; 
先别看后面的+1 
统计每一位会增加的次数以及会减少的次数。

  1. 先看会增加的,x表示左边小的个数,y表示右边小或等于的个数 
    当i=1, x = 0, y = 0, det = 0 
    当i=2, x = 1, y = 0, det = (1+0+0)*2 
    当i=3, x = 2, y = 0, det = (2+0+0)*3 
    当i=4, x = 3, y = 0, det = 3*4 
    当i=5, x = 4, y = 0, det = 4*5

  2. 再看会减少的,x表示左边大的个数,y表示右边大或等于的个数 
    当i=1, x = 0, y = 4, det = 4*1 
    当i=2, x = 0, y = 3, det = 3*2 
    当i=3, x = 0, y = 2, det = 2*3 
    当i=4, x = 0, y = 1, det = 1*4 
    当i=5, x = 0, y = 0, det = 0*5

所以,ans=2+6+12+20-4-6-6-4=20 
由于还要+1,所以还要加n*(n+1)/2。

我们只要用单调栈求出需要的x和y就行了。

代码

/*
*  Author:      illuz <iilluzen[at]gmail.com>
*  File:        C.cpp
*  Create Date: 2014-06-07 15:41:15
*  Descripton:   
*/

#include <cstdio>
#include <iostream>
#include <stack>
using namespace std;
typedef long long ll;

const int N = 1e5 + 10;

stack<int> s, ss;

int t, n;
int a[N], big[N], bige[N];
ll ans, tmp;

int main()
{
	scanf("%d", &t);
	for (int cas = 1; cas <= t; cas++) {
		scanf("%d", &n);
		while (!s.empty())
			s.pop();
		while (!ss.empty())
			ss.pop();
		for (int i = 0; i < n; i++) {
			scanf("%d", &a[i]);
			// 左边小的个数
			while (!s.empty() && a[s.top()] > a[i])
				s.pop();
			if (s.empty())
				big[i] = i;
			else
				big[i] = i - s.top() - 1;
			s.push(i);
			// 左边大的个数
			while (!ss.empty() && a[ss.top()] < a[i])
				ss.pop();
			if (ss.empty())
				bige[i] = i;
			else
				bige[i] = i - ss.top() - 1;
			ss.push(i);
		}
		while (!s.empty())
			s.pop();
		while (!ss.empty())
			ss.pop();
		ans = 0;
		for (int i = n - 1; i >= 0; i--) {
			// 右边小或等于的个数
			while (!s.empty() && a[s.top()] >= a[i])
				s.pop();
			if (s.empty())
				tmp = n - i - 1;
			else
				tmp = s.top() - i - 1;
			ans -= (tmp + big[i] + tmp * big[i]) * a[i];
			s.push(i);
			// 右边大或等于的个数
			while (!ss.empty() && a[ss.top()] <= a[i])
				ss.pop();
			if (ss.empty())
				tmp = n - i - 1;
			else
				tmp = ss.top() - i - 1;
			ans += (tmp + bige[i] + tmp * bige[i]) * a[i];
			ss.push(i);
		}
		ans += n * (n + 1) / 2;
		printf("Case %d: ", cas);
		cout << ans << endl;
	}
	return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值