Imbalanced Array CodeForces - 817D
考察:单调栈
错误思路:
枚举滑动窗口大小,从头到尾计算.TLE O(n2)
正确思路:
根据a[i]对答案的贡献来计算,由题意得ans += (r-l)*a[i] 其中r是a[i]作为最大值的区间个数,l是a[i]作为最小值的区间个数.那么问题是如何计算区间个数.
首先明白单调栈和单调队列的区别.单调队列也就是滑动窗口是求出一段区间内的最值.而单调栈是可以找到a[i]往左的第一个比a[i]小(大)的值,也可以用来求!~i的最值.根据这道题区间个数可以由1~i中,a[i]作为最小(大)值的左边界,i~n中,a[i]作为最小值(大)的右边界算出.区间个数 = 左边界长度*右边界长度.
由之前的单调栈的用处可知,左右边界可由单调栈计算.
1 #include <iostream> 2 #include <cstring> 3 using namespace std; 4 typedef long long LL; 5 const int N = 1000010; 6 int L1[N],R1[N],L2[N],R2[N]; 7 int a[N],m,s1[N],t1,s2[N],t2; 8 LL solve() 9 { 10 LL res = 0; 11 for(int i=1;i<=m;i++) 12 { 13 while(t1&&a[s1[t1]]<=a[i]) --t1;//比a[i]大的 14 while(t2&&a[s2[t2]]>=a[i]) --t2;//比a[i]小的 15 if(!t1) L1[i] = 1;//做最大值的左边界 16 else L1[i] = s1[t1]+1; 17 if(!t2) L2[i] = 1; 18 else L2[i] = s2[t2]+1; 19 s1[++t1] = i,s2[++t2] = i; 20 } 21 t1 = t2 = 0; 22 for(int i=m;i>0;i--) 23 { 24 while(t1&&a[s1[t1]]<a[i]) --t1; 25 while(t2&&a[s2[t2]]>a[i]) --t2; 26 if(!t1) R1[i] = m;//做最大值的右边界 27 else R1[i] = s1[t1]-1; 28 if(!t2) R2[i] = m; 29 else R2[i] = s2[t2]-1; 30 s1[++t1] = i,s2[++t2] = i; 31 } 32 for(int i=1;i<=m;i++) 33 { 34 LL t=(LL)(R1[i]-i+1)*(i-L1[i]+1)-(LL)(R2[i]-i+1)*(i-L2[i]+1); 35 res+=t*a[i]; 36 } 37 return res; 38 } 39 int main() 40 { 41 scanf("%d",&m); 42 for(int i=1;i<=m;i++) scanf("%d",&a[i]); 43 LL res = solve(); 44 printf("%lld\n",res); 45 return 0; 46 }