1. 程式人生 > >1215 】陣列的寬度 (單調棧 或 分治 或 單調佇列,算貢獻,需去重)

1215 】陣列的寬度 (單調棧 或 分治 或 單調佇列,算貢獻,需去重)

題幹:

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;
}

還有幾個好的題解:(暫時還未看)