【51Nod - 1215 】数组的宽度 (单调栈 或 分治 或 单调队列,算贡献,需去重)

版权声明:欢迎学习我的博客,希望ACM的发展越来越好~ https://blog.csdn.net/qq_41289920/article/details/82927413

题干:

N个整数组成的数组,定义子数组aii..ajj的宽度为:max(ai..aj) - min(ai..aj),求所有子数组的宽度和。

Input

第1行:1个数N,表示数组的长度。(1 <= N <= 50000) 
第2 - N + 1行:每行1个数,表示数组中的元素(1 <= Aii <= 50000)

Output

输出所有子数组的宽度和。

Sample Input

5
1
2
3
4
5

Sample Output

20

解题报告:

    这题显然不能枚举区间然后分别计算,所以很多技巧根本不需要考虑(比如排序一下?)

    然后我们考虑枚举每一个元素,计算他对答案的贡献。

    记得去重,也就是,一边算 严格单调,一边是 不严格单调,这样就可以保证不重不漏。(像 5 1 2 1 3 3 这样的样例,算贡献时(2,4)这种区间 只需要算一次。所以单调栈的时候一边是严格单调,一边是不严格单调)这个去重的方法很巧妙啊、

AC代码:

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int MAX = 50000 + 5;
ll a[MAX],maxx[MAX],minn[MAX];
int l[MAX],r[MAX],L[MAX],R[MAX];//左侧第一个比我小的,右侧第一个比我小的。
stack<int> sk;
int main()
{
	int n;
	cin>>n;
	for(int i = 1; i<=n; i++) scanf("%lld",a+i);
	//从左到右找第一个比我小的,所以从左到右维护一个单调递增栈。
	for(int i = 1; i<=n; i++) {
		while(!sk.empty() && a[sk.top()] > a[i]) sk.pop();
		if(sk.size()) l[i] = sk.top();
		else l[i] = 0;
		sk.push(i);
//		printf("%d %d\n",i,l[i]);
	}
	while(!sk.empty()) sk.pop();
	//从右到左找第一个比我小的,所以维护从右向左维护一个单调递减栈。
	for(int i = n; i>=1; i--) {
		while(!sk.empty() && a[sk.top()] >= a[i]) sk.pop();
		if(sk.size()) r[i] = sk.top();
		else r[i] = n+1;
		sk.push(i);
//		printf("%d %d\n",i,r[i]);
	}
	for(int i = 1; i<=n; i++) minn[i] = (r[i] - i - 1) * (i-l[i]-1) + (r[i]-l[i]-1);
	while(!sk.empty()) sk.pop();
	//从左到右找第一个比我大的,所以从左向右维护一个单调递减栈,
	for(int i = 1; i<=n; i++) {
		while(!sk.empty() && a[sk.top()] < a[i]) sk.pop();
		if(sk.size()) L[i] = sk.top();
		else L[i] = 0;
		sk.push(i);
	}
	while(!sk.empty()) sk.pop();
	for(int i = n; i>=1; i--) {
		while(!sk.empty() && a[sk.top()] <= a[i]) sk.pop();
		if(sk.size()) R[i] = sk.top();
		else R[i] = n+1;
		sk.push(i);
	}
	for(int i = 1; i<=n; i++) maxx[i] = (R[i] - i-1) * (i-L[i]-1) + (R[i]-L[i]-1);
//	printf("yingyingying\n");
//	for(int i = 1; i<=n; i++) {
//		printf("%lld %lld\n",minn[i],maxx[i]);
//	}
	ll ans = 0;
	for(int i = 1; i<=n; i++) {
		ans += a[i] * (maxx[i] - minn[i]);
	}
	printf("%lld\n",ans);
    return 0;
}

还有几个好的题解:(暂时还未看)

http://www.itdaan.com/blog/2017/09/18/fb224770ef3801dcce5fcac76c36b4df.html

http://www.itdaan.com/blog/2017/08/22/df09138e3e52fc862172e8c8875d95ff.html

猜你喜欢

转载自blog.csdn.net/qq_41289920/article/details/82927413