【51Nod - 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 5Sample 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
總結
以上是生活随笔為你收集整理的【51Nod - 1215 】数组的宽度 (单调栈 或 分治 或 单调队列,算贡献,需去重)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: schedul2.exe - sched
- 下一篇: *【CF#510C】Fox And Na