Description
给定一个长度为 (n) 的排列 (p),求有多少区间 ([l,r]) 满足 (p[l]+p[r]=max{p[i]}),其中 (l le i le r)
Solution
单调栈预处理出每个元素的控制区间(以它为最大值的区间)
枚举最大值位置 (i),于是 (l in [l[i],i], r in [i,r[i]])
考察两个区间的长度,在小的那个中枚举,则只需要检查差是否在大区间中出现
用排列的逆来检查,值 (x) 在 (p_l,...,p_r) 中出现,即 (l le I_x le r),其中 (I) 是 (p) 的逆
显然每个元素被枚举次数的上界为 (O(log n)),于是时间复杂度为 (O(n log n))
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 200005;
const int dbg = 1;
int p[N],n,inv[N],l[N],r[N];
stack<int> s;
bool check(int x,int l,int r)
{
if(x<0 || x>n) return 0;
return l<=inv[x] && inv[x]<=r;
}
signed main()
{
ios::sync_with_stdio(false);
cin>>n;
for(int i=1;i<=n;i++) cin>>p[i], inv[p[i]]=i;
for(int i=1;i<=n;i++)
{
while(s.size() && p[s.top()]<p[i]) s.pop();
if(s.size()) l[i]=s.top()+1;
else l[i]=1;
s.push(i);
}
while(s.size()) s.pop();
for(int i=n;i>=1;--i)
{
while(s.size() && p[s.top()]<p[i]) s.pop();
if(s.size()) r[i]=s.top()-1;
else r[i]=n;
s.push(i);
}
if(dbg)
{
cout<<"monostack output: "<<endl;
for(int i=1;i<=n;i++) cout<<l[i]<<" ";
cout<<endl;
for(int i=1;i<=n;i++) cout<<r[i]<<" ";
cout<<endl<<endl;
}
int ans=0;
for(int i=1;i<=n;i++)
{
int pl,pr,ql,qr;
if(i-l[i] < r[i]-i)
{
pl=l[i];
pr=i;
ql=i;
qr=r[i];
}
else
{
pl=i;
pr=r[i];
ql=l[i];
qr=i;
}
if(dbg)
{
cout<<"round "<<i<<": "<<pl<<","<<pr<<" "<<ql<<","<<qr<<endl;
}
int tans=0;
for(int j=pl;j<=pr;j++)
{
if(check(p[i]-p[j],ql,qr))
{
++tans;
}
}
ans+=tans;
if(dbg) cout<<" + "<<tans<<" = "<<ans<<endl;
}
cout<<ans<<endl;
}