51nod 1215 單調棧/叠代
阿新 • • 發佈:2017-08-23
允許 typedef 端點 修改 min end tput bsp http
Output
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)
輸出所有子數組的寬度和。Input示例
5 1 2 3 4 5Output示例
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 單調棧/叠代