1. 程式人生 > >51nod 1215 單調棧/叠代

51nod 1215 單調棧/叠代

允許 typedef 端點 修改 min end tput bsp http

http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1215

1215 數組的寬度技術分享

題目來源: Javaman 基準時間限制:1 秒 空間限制:131072 KB 分值: 80 難度:5級算法題 技術分享 收藏 技術分享 關註 N個整數組成的數組,定義子數組a[i]..a[j]的寬度為:max(a[i]..a[j]) - min(a[i]..a[j]),求所有子數組的寬度和。 Input
第1行:1個數N,表示數組的長度。(1 <= N <= 50000)
第2 - N + 1行:每行1個數,表示數組中的元素(1 <= A[i] <= 50000)
Output
輸出所有子數組的寬度和。
Input示例
5
1
2
3
4
5
Output示例
20
感覺很經典的題目。
首先我們不可能枚舉出所有的子區間,顯然時空是不允許的,那就要從元素入手,我們只要知道每個元素被作為最大最小值得次數答案就出來了,問題轉化為求元素作為最值的次數。
可以找到當前元素作為最大/小值時對應的最大的區間左右端點,然後組合計算一下就是答案了。找這個左右端點時可以用單調棧也可以叠代搜索,stl貌似要慢一些。
正確性在於找端點時滿足決策單調性,例如找最大值左端點時,這個元素左側的元素如果大於他,那顯然左端點就是他本身了,此時就是一個單調遞減棧,大於棧頂元素時左端點就可以用棧頂
元素的左端點代替;
總之就一句話,大於左側的元素,一定大於所有左側元素能大於的元素。
還有就是第一次WA了因為重復計算了, 只要稍微修改一下為左側不嚴格右側嚴格的查找就好了。
 1 #include <iostream>
 2 #include<algorithm>
 3 #include<stack>
 4 #include<cstdio>
 5 using namespace std;
 6 typedef long long LL;
 7 const int MAX = 50005;
 8 int a[MAX], l1[MAX], r1[MAX], l2[MAX], r2[MAX];
 9 int maxt[MAX], mint[MAX];
10 stack<int>S;
11 int main()
12
{ 13 int N, i, j, k; 14 scanf("%d", &N); 15 for (i = 1;i <= N;++i) scanf("%d", a + i); 16 for (i = 1;i <= N;++i) 17 { 18 if (S.empty() || a[i] < a[S.top()]) { 19 l1[i] = i; 20 S.push(i); 21 } 22 else { 23 while (!S.empty() && a[S.top()] <= a[i]) { 24 l1[i] = l1[S.top()]; 25 S.pop(); 26 } 27 S.push(i); 28 } 29 }while (!S.empty()) S.pop(); 30 for (i = N;i >=1;--i) 31 { 32 if (S.empty() || a[i] <= a[S.top()]) { 33 r1[i] = i; 34 S.push(i); 35 } 36 else { 37 while (!S.empty() && a[S.top()] < a[i]) { 38 r1[i] = r1[S.top()]; 39 S.pop(); 40 } 41 S.push(i); 42 } 43 }while (!S.empty()) S.pop(); 44 for (i = 1;i <= N;++i) 45 { 46 maxt[i] += (r1[i]-l1[i])+(i-l1[i])*(r1[i]-i); 47 } 48 for (i = 1;i <= N;++i) 49 { 50 if (S.empty() || a[i] > a[S.top()]) { 51 l2[i] = i; 52 S.push(i); 53 } 54 else { 55 while (!S.empty() && a[S.top()] >=a[i]) { 56 l2[i] = l2[S.top()]; 57 S.pop(); 58 } 59 S.push(i); 60 } 61 }while (!S.empty()) S.pop(); 62 for (i = N;i>=1;--i) 63 { 64 if (S.empty() || a[i] >= a[S.top()]) { 65 r2[i] = i; 66 S.push(i); 67 } 68 else { 69 while (!S.empty() && a[S.top()] > a[i]) { 70 r2[i] = r2[S.top()]; 71 S.pop(); 72 } 73 S.push(i); 74 } 75 }while (!S.empty()) S.pop(); 76 for (i = 1;i <= N;++i) 77 { 78 mint[i] += (-l2[i]+r2[i])+(i-l2[i])*(r2[i]-i); 79 } 80 LL ans = 0; 81 for (i = 1;i <= N;++i) 82 { 83 ans += (LL)a[i] * (maxt[i]-mint[i]); 84 } 85 printf("%lld\n", ans); 86 return 0; 87 }

叠代:

 1 #include <iostream>
 2 #include<algorithm>
 3 #include<stack>
 4 #include<cstdio>
 5 using namespace std;
 6 typedef long long LL;
 7 const int MAX = 50005;
 8 int a[MAX], l1[MAX], r1[MAX], l2[MAX], r2[MAX];
 9 int maxt[MAX], mint[MAX];
10 int main()
11 {
12     int N, i, j, k;
13     scanf("%d", &N);
14     for (i = 1;i <= N;++i) scanf("%d", a + i);
15     for (i = 1;i <= N;++i) {
16         l1[i] = r1[i] = i;
17         l2[i] = r2[i] = i;
18     }
19     for (i = 1;i <= N;++i) {
20         while (l1[i] != 1 && a[i] >= a[l1[i] - 1]) 
21             l1[i] = l1[l1[i]-1];
22         while (l2[i] != 1 && a[i] <= a[l2[i] - 1])
23             l2[i] = l2[l2[i] - 1];
24     }
25     for (i = N;i >= 1;--i) {
26         while (r1[i] != N&&a[i] > a[r1[i] + 1])
27             r1[i] = r1[r1[i] + 1];
28         while (r2[i] != N&&a[i] < a[r2[i] + 1])
29             r2[i] = r2[r2[i] + 1];
30     }
31     LL ans = 0;
32     for (i = 1;i <= N;++i) {
33         ans += (LL)a[i] * ((r1[i] - l1[i]) + (i - l1[i])*(r1[i] - i)- (-l2[i] + r2[i]) - (i - l2[i])*(r2[i] - i));
34     }
35     cout << ans << endl;
36     //system("pause");
37     return 0;
38 }

51nod 1215 單調棧/叠代