我们枚举最大值的那个点pos, 然后枚举l-pos中的值, 在pos-r中查有多少个<= a[pos]/a[i]
用主席树来完成(先离散化), 在序列随机的情况下O(nlogn^2)
#include<bits/stdc++.h>
#define N 100050
#define LL long long
#define Re register
using namespace std;
int a[N],b[N],n,siz,Max;
int cnt,rt[N]; LL ans;
struct Node{
int ls,rs,val;
}t[N*40];
int read(){
int cnt=0; char ch=0;
while(!isdigit(ch))ch=getchar();
while(isdigit(ch))cnt=cnt*10+(ch-'0'),ch=getchar();
return cnt;
}
void Build(int &x,int l,int r){
x = ++cnt;
if(l==r) return;
int mid = (l+r) >> 1;
Build(t[x].ls, l, mid);
Build(t[x].rs, mid+1, r);
}
void Insert(int &x,int last,int l,int r,int pos){
x = ++cnt;
t[x] = t[last]; t[x].val++;
if(l==r) return;
int mid = (l+r) >> 1;
if(pos<=mid) Insert(t[x].ls,t[last].ls,l,mid,pos);
else Insert(t[x].rs,t[last].rs,mid+1,r,pos);
}
int Quary(int now,int pre,int l,int r,int L,int R){
if(L<=l && r<=R) return t[now].val - t[pre].val;
int mid = (l+r) >> 1, ans = 0;
if(L<=mid) ans += Quary(t[now].ls, t[pre].ls, l, mid, L, R);
if(R>mid) ans += Quary(t[now].rs, t[pre].rs, mid+1, r, L ,R);
return ans;
}
void Solve(int l,int r){
if(l>r) return;
if(l==r){ans += (a[l]==1); return;}
int pos=0;
for(Re int i=l;i<=r;i++)
if(!pos || a[i] > a[pos]) pos = i;
if(pos-l+1 <= r-pos+1){
for(Re int i=l;i<=pos;i++){
int limit = a[pos] / a[i];
int x = upper_bound(b+1,b+siz+1,limit) - b - 1;
if(x>0) ans += (LL)Quary(rt[r], rt[pos-1], 1, n, 1, x);
}
}
else{
for(Re int i=pos;i<=r;i++){
int limit = a[pos] / a[i];
int x = upper_bound(b+1,b+siz+1,limit) - b - 1;
if(x>0) ans += (LL)Quary(rt[pos], rt[l-1], 1, n, 1, x);
}
}
Solve(l,pos-1); Solve(pos+1,r);
}
int main(){
n = read();
for(Re int i=1;i<=n;i++){
a[i] = b[i] = read();
} sort(b+1,b+n+1);
siz = unique(b+1,b+n+1) - (b+1);
Build(rt[0],1,n);
for(Re int i=1;i<=n;i++){
int x = lower_bound(b+1,b+siz+1,a[i]) - b;
Insert(rt[i],rt[i-1],1,n,x);
}
Solve(1,n);
printf("%lld",ans); return 0;
}