题面:http://codeforces.com/contest/1156/problem/E
Luogu翻译:https://www.luogu.com.cn/problem/CF1156E
话说Luogu要改域名了。
大意:给定一个长度为n的排列p,求有多少区间[l,r]满足,p[l]+p[r]=max{p[i]},其中l<=i<=r
据说可以笛卡尔树。
可是我不会。
那么就瞎搞。
预处理出左边第一个比a[i]大的数的位置,记为L[i]
R[i]同理为右边。
这个可以用单调栈求。
然后就可以枚举l和r了。
但是显然这样会爆炸。
但是由于题目的限制,可以只枚举一边。
另外一边直接查询有没有。
比如枚举了l,那么p[r]=pmax-p[l]
只用知道右边有没有p[r]就可以了。
代码如下:
#include<bits/stdc++.h> using namespace std; const int maxn=2*1e5+10; int n,a[maxn],pos[maxn]; long long ans; int L[maxn],R[maxn],s[maxn]; int main() { scanf("%d",&n); for(int i=1;i<=n;i++){ scanf("%d",&a[i]); pos[a[i]]=i; } int top=0; for(int i=1;i<=n;i++){ while(top && a[s[top]]<a[i]) top--; L[i]=s[top]; s[++top]=i; } top=0;s[top]=n+1; for(int i=n;i;i--){ while(top && a[s[top]]<a[i]) top--; R[i]=s[top]; s[++top]=i; } for(int i=1;i<=n;i++){ if(i-L[i]<R[i]-i){ for(int j=L[i]+1;j<i;j++) if(pos[a[i]-a[j]]>i && pos[a[i]-a[j]]<R[i]) ans++; }else{ for(int j=i+1;j<R[i];j++) if(pos[a[i]-a[j]]<i && pos[a[i]-a[j]]>L[i]) ans++; } } printf("%d\n",ans); return 0; }
原文地址:https://www.cnblogs.com/ChrisKKK/p/11521144.html
时间: 2024-11-08 07:33:10