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 }

 

posted @ 2021-03-31 13:24  acmloser  阅读(59)  评论(0编辑  收藏  举报