【51Nod - 1215 】数组的宽度 (单调栈 或 分治 或 单调队列,算贡献,需去重)
題干:
N個(gè)整數(shù)組成的數(shù)組,定義子數(shù)組aii..ajj的寬度為:max(ai..aj) - min(ai..aj),求所有子數(shù)組的寬度和。
Input
第1行:1個(gè)數(shù)N,表示數(shù)組的長(zhǎng)度。(1 <= N <= 50000)?
第2 - N + 1行:每行1個(gè)數(shù),表示數(shù)組中的元素(1 <= Aii?<= 50000)
Output
輸出所有子數(shù)組的寬度和。
Sample Input
5 1 2 3 4 5Sample Output
20解題報(bào)告:
? ? 這題顯然不能枚舉區(qū)間然后分別計(jì)算,所以很多技巧根本不需要考慮(比如排序一下?)
? ? 然后我們考慮枚舉每一個(gè)元素,計(jì)算他對(duì)答案的貢獻(xiàn)。
? ? 記得去重,也就是,一邊算 嚴(yán)格單調(diào),一邊是 不嚴(yán)格單調(diào),這樣就可以保證不重不漏。(像 5 1 2 1 3 3 這樣的樣例,算貢獻(xiàn)時(shí)(2,4)這種區(qū)間 只需要算一次。所以單調(diào)棧的時(shí)候一邊是嚴(yán)格單調(diào),一邊是不嚴(yán)格單調(diào))這個(gè)去重的方法很巧妙啊、
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];//左側(cè)第一個(gè)比我小的,右側(cè)第一個(gè)比我小的。 stack<int> sk; int main() {int n;cin>>n;for(int i = 1; i<=n; i++) scanf("%lld",a+i);//從左到右找第一個(gè)比我小的,所以從左到右維護(hù)一個(gè)單調(diào)遞增棧。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();//從右到左找第一個(gè)比我小的,所以維護(hù)從右向左維護(hù)一個(gè)單調(diào)遞減棧。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();//從左到右找第一個(gè)比我大的,所以從左向右維護(hù)一個(gè)單調(diào)遞減棧,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; }?
?
還有幾個(gè)好的題解:(暫時(shí)還未看)
http://www.itdaan.com/blog/2017/09/18/fb224770ef3801dcce5fcac76c36b4df.html
http://www.itdaan.com/blog/2017/08/22/df09138e3e52fc862172e8c8875d95ff.html
總結(jié)
以上是生活随笔為你收集整理的【51Nod - 1215 】数组的宽度 (单调栈 或 分治 或 单调队列,算贡献,需去重)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: schedul2.exe - sched
- 下一篇: *【CF#510C】Fox And Na