题解:AT_abc140_e [ABC140E] Second Sum
声明:这并不是一篇算法独特的题解,相关方法此篇题解已有,但绝对更为详细。
广告:个人Blog同步链接。
题意分析
当
由此我们开始做题。
计算合法区间数
显然,当且仅当区间中有且仅有一个数大于
那么我们考虑算出,对于每一个
如果我们找出了
那么我们所需要的会对答案造成贡献的区间就不会包含
既然如此,令合法区间为
图示:
当
同样地,当
那么
则最终答案为
但这时我们需要注意的是,这四个数都有可能不会存在,那么初值就变得十分重要,甚至会影响最终答案的正确性。当然,你不嫌麻烦你特判也行。
-
如果你的下标从
1 开始:for(int i=1;i<=n;i++){ l[i]=dl[i]=0; r[i]=dr[i]=n+1; } -
如果你的下标从
0 开始:for(int i=0;i<n;i++){ l[i]=dl[i]=-1; r[i]=dr[i]=n; }
(其实就是类似于“值域两端”)
解释一下为什么:(下标从
以
首先,
如果
如果
这样,我们便可以
如何计算四个数的位置
如果你不知道 set
说了这么多,我们还是不知道如何求出
事实上,我们仅仅需要从大至小向 set 中加入
令
这时我们用 set 中执行 lower_bound(p[i])(或者 upper_bound(p[i]) 也行,因为
那么 set,代表
而 set 的最后一个元素(不然越界)时,找到 set 的有序特性且
对于 set 内
那么就有
注意判定越界。
最后记得将 set 即可。
不会有人不会算前驱后继节点吧。
使用 next() 和 prev() 即可。
虽然说对迭代器进行自减运算、自加运算,或者进行数学运算后强制类型转换也行,但是确实没有这两个简单。
注意事项
-
- 开
long long。
AC代码
//#include<bits/stdc++.h>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<iomanip>
#include<cstdio>
#include<string>
#include<vector>
#include<cmath>
#include<ctime>
#include<deque>
#include<queue>
#include<stack>
#include<list>
#include<set>
using namespace std;
typedef long long ll;
const int N=2e5;
ll n,a[N+1],p[N+1],l[N+1],dl[N+1],r[N+1],dr[N+1];
bool cmp(ll x,ll y){
if(a[x]!=a[y])return a[x]>a[y];
return x<y;
}
int main(){
/*freopen("test.in","r",stdin);
freopen("test.out","w",stdout);*/
scanf("%lld",&n);
for(ll i=1;i<=n;i++)scanf("%lld",a+i);
for(ll i=1;i<=n;i++){
p[i]=i;
l[i]=dl[i]=0;
r[i]=dr[i]=n+1;
}sort(p+1,p+n+1,cmp);
set<ll>s;
for(ll i=1;i<=n;i++){
auto pl=s.lower_bound(p[i]);
if(pl!=s.end()){
r[p[i]]=*pl;
if(next(pl)!=s.end())dr[p[i]]=*next(pl);
}if(pl!=s.begin()){
pl--;
l[p[i]]=*pl;
if(pl!=s.begin())dl[p[i]]=*prev(pl);
}s.insert(p[i]);
}ll ans=0;
for(ll i=1;i<=n;i++)ans+=a[i]*((l[i]-dl[i])*(r[i]-i)+(i-l[i])*(dr[i]-r[i]));
printf("%lld\n",ans);
/*fclose(stdin);
fclose(stdout);*/
return 0;
}