题意:
给一个n的排列,求满足a[l]+a[r]=max(l,r)的(l,r)对数,max(l,r)指的是l到r之间的最大a[p]
n<=2e5
思路:
先用单调栈处理出每个点能扩展的l[i],r[i]
搜索以每个点为最大值时的贡献,对每个点只搜索它左边部分或右边部分最小的那个
可以证明,每个点最多被搜到logn次,类似于启发式合并的思想,
复杂度为nlogn
代码:
#include<iostream> #include<cstdio> #include<algorithm> #include<cmath> #include<cstring> #include<string> #include<stack> #include<queue> #include<deque> #include<set> #include<vector> #include<map> #include<functional> #define fst first #define sc second #define pb push_back #define mem(a,b) memset(a,b,sizeof(a)) #define lson l,mid,root<<1 #define rson mid+1,r,root<<1|1 #define lc root<<1 #define rc root<<1|1 #define lowbit(x) ((x)&(-x)) #define LLONG_MAX 9223372036854775807 using namespace std; typedef double db; typedef long double ldb; typedef long long ll; typedef long long LL; typedef unsigned long long ull; typedef pair<int,int> PI; typedef pair<ll,ll> PLL; const db eps = 1e-6; const int mod = 1e9+7; const int maxn = 2e6+11; const int maxm = 1e5+100; const int inf = 0x3f3f3f3f; const db pi = acos(-1.0); int a[maxn]; int l[maxn],r[maxn]; int idx[maxn]; ll ans = 0; void gao(int x){ int L,R; int pL,pR; if(x-l[x]<r[x]-x){ L=l[x]; R=x-1; pL=x+1; pR=r[x]; } else{ pL=l[x]; pR=x-1; L=x+1; R=r[x]; } for(int i = L; i <= R; i++){ int y = a[x]-a[i]; if(idx[y]>=pL&&idx[y]<=pR)ans++; } } int main(){ int n; scanf("%d", &n); for(int i = 1; i <= n; i++){ scanf("%d", &a[i]); idx[a[i]]=i; l[i] = r[i] = i; } a[0]=a[n+1]=n+1; for(int i = 1; i <= n; i++){ while(a[l[i]-1] <= a[i]){ l[i] = l[l[i]-1]; } } for(int i = n; i >= 1; i--){ while(a[r[i]+1] <= a[i]){ r[i] = r[r[i]+1]; } } ans = 0; for(int i = 1; i <= n; i++){ gao(i); } printf("%lld",ans); return 0; }