问题 J: 小C的数学问题(单调栈)

题目链接
题目描述
小C是个云南中医学院的大一新生,在某个星期二,他的高数老师扔给了他一个问题。
让他在1天的时间内给出答案。
但是小C不会这问题,现在他来请教你。
请你帮他解决这个问题。
有n个数,每个数有权值。
数学老师定义了区间价值为区间和乘上区间内的最小值。
现在要你找出有最大区间价值的区间是什么,并输出区间价值。

输入
每个输入文件只包含单组数据。
第一行一个整数n。(1 <= n <= 100000)
第二行n个整数a_1,a_2,…,a_n。(0 <= a_i <= 1000000)

输出
第一行输出一个整数,表示最大的区间价值。
第二行输出两个整数,表示区间的起点和终点。
保证答案唯一。

样例输入
6
10 1 9 4 5 9

样例输出
108
3 6

把每个数当作最小值,找寻它的左右区间,最后遍历一遍输出结果,具体实现看代码

#include
#include
#include
using namespace std;
const int N = 100005;
typedef long long ll;
ll n,ans,t,l,r,a[N],sum[N],fward[N],bward[N];//注意开long long 类型
stack <pair<ll,ll> > stk;//> >中间有个空格 
int main(){
	scanf("%lld",&n);
	for(int i = 1;i <= n;i++){//下标从1开始方便后面处理
		scanf("%lld",a + i);
		sum[i] = sum[i - 1] + a[i];//先求前缀和
	}
	for(int i = 1;i <= n;i++){//把每个数当作区间最小值,先找每个数的左区间,不懂的拿样例,模拟即可,数据也不多(狗头保命)
		fward[i] = i;
		while(!stk.empty() && a[i] <= stk.top().first){
			fward[i] = stk.top().second;
			stk.pop();
		}
		stk.push({a[i],fward[i]});
	}
	while(!stk.empty()) stk.pop();
	for(int i = n;i;i--){//把每个数当作区间最小值,先找每个数的右区间,不懂的拿样例,模拟即可,数据也不多(狗头保命)
		bward[i] = i;
		while(!stk.empty() && a[i] <= stk.top().first){
			bward[i] = stk.top().second;
			stk.pop();
		}
		stk.push({a[i],bward[i]});
	}
	ans = -1; // 数据中含有0,所以最小值设为-1
	for(int i = 1;i <= n;i++){
		t = a[i] * (sum[bward[i]] - sum[fward[i] - 1]);//1 2 3 4 5 求2~4(下标)的值 sum[4] - s[4 - 2 - 1]
		if(t > ans){
			ans = t;
			l = fward[i];
			r = bward[i];
		}
	}
	printf("%lld\n%lld %lld\n",ans,l,r);
	return 0;
}

你可能感兴趣的:(栈)