小D有一个数列a。
当一个数对(i,j)满足a[i]*a[j]<=max[a[i],a[i+1],...a[j]]的时候
才被统计。
询问有多少对数对。
做法:
先单调栈处理出每个数作为最大值的区间,为了避免重复计算,这里对左边找第一个>=a[i]的数,对右边找第一个>a[i]的数,这样就可以去重。
然后对每个数,根据这个数的位置可以划分为左区间和右区间,对于这个东西可以每次枚举较小的那个区间,这样启发式的枚举,时间复杂度是O(nlognlogn)的
//对每个数处理出它作为最大值的左右区间
//然后枚举较短的那个区间计算较长的那个区间
//均摊时间复杂度O(nlogn)
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
const int M=maxn*40;
int n,a[maxn],L[maxn],R[maxn];
int T[maxn],c[M],lson[M],rson[M],tot;
int build (int l,int r) {
int u=++tot;
if (l==r) {
c[u]=0;
return u;
}
int mid=(l+r)>>1;
lson[u]=build(l,mid);
rson[u]=build(mid+1,r);
c[u]=c[lson[u]]+c[rson[u]];
return u;
}
int up (int u,int l,int r,int p,int v) {
int newRoot=++tot;
c[newRoot]=c[u]+v;
if (l==r) return newRoot;
int mid=(l+r)>>1;
lson[newRoot]=lson[u];
rson[newRoot]=rson[u];
if (p<=mid) lson[newRoot]=up(lson[u],l,mid,p,v);
if (p>mid) rson[newRoot]=up(rson[u],mid+1,r,p,v);
return newRoot;
}
int query (int lr,int rr,int l,int r,int L,int R) {
if (L>R) return 0;
if (l>=L&&r<=R) return c[rr]-c[lr];
int mid=(l+r)>>1;
int ans=0;
if (L<=mid) ans+=query(lson[lr],lson[rr],l,mid,L,R);
if (R>mid) ans+=query(rson[lr],rson[rr],mid+1,r,L,R);
return ans;
}
int t[maxn],mm;
int main () {
scanf("%d",&n);
for (int i=1;i<=n;i++) scanf("%d",a+i),t[i]=a[i],L[i]=1,R[i]=n;
sort(t+1,t+n+1);
mm=unique(t+1,t+n+1)-t-1;
for (int i=1;i<=n;i++) a[i]=upper_bound(t+1,t+mm+1,a[i])-t-1;
stack<int> st;
for (int i=1;i<=n;i++) {
while(st.size()) {
if (a[st.top()]>=a[i]) {
L[i]=st.top()+1;
break;
}
st.pop();
}
st.push(i);
}
while (st.size()) st.pop();
for (int i=n;i>=1;i--) {
while (st.size()) {
if (a[st.top()]>a[i]) {
R[i]=st.top()-1;
break;
}
st.pop();
}
st.push(i);
}
long long ans=0;
T[0]=build(1,mm);
//7 7 7 7 7
for (int i=1;i<=n;i++) T[i]=up(T[i-1],1,mm,a[i],1);
for (int i=1;i<=n;i++) {
int x=i-L[i]+1;
int y=R[i]-i+1;
if (x<=y) {
for (int j=L[i];j<=i;j++) {
int re=(t[a[i]]/t[a[j]]);
//printf("%d
",re);
int p=upper_bound(t+1,t+mm+1,re)-t-1;
ans+=query(T[i-1],T[R[i]],1,mm,1,p);
}
}
else {
for (int j=i;j<=R[i];j++) {
int re=(t[a[i]]/t[a[j]]);
//printf("%d
",re);
int p=upper_bound(t+1,t+mm+1,re)-t-1;
ans+=query(T[L[i]-1],T[i],1,mm,1,p);
}
}
}
printf("%lld
",ans);
}