找到满足 a[l]*a[r]<=a[pos],a[pos]为区间最大值。的区间个数
又是套路,区间最大值+找满足题意的区间个数。
很容易想到启发式分治
枚举少的一端,另一端查询区间小于等于x的数的个数即可。这个操作用主席树维护就行。
具体过程可以仿照我前几篇启发式分治的过程,很清楚。
这里注意主席树查询的是小于等于x的数。但我们加上离散化后,你要用upper_bound找到严格大于k的数,
再求小于等于k-1的数的个数才能对应,还有就是线段树老生常谈,不支持0.。又wa在了这里。。。
# //KX
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef double db;
const int M= 1e5+7;
int a[M],li[M],ali[M];
int lg[M],dp[M][30];
int sum[M*22],rt[M*22],ls[M*22],rs[M*22];
int sz,cnt;
ll ans=0;
void RMQ(int n)
{
for(int i=1;i<=n;i++)dp[i][0]=i;
for(int j=1;(1<<j)<=n;j++)//区间长度
for(int i=1;i+(1<<j)-1<=n;i++)//区间左端点
{
dp[i][j]=a[dp[i][j-1]]>=a[dp[i+(1<<j-1)][j-1]]?dp[i][j-1]:dp[i+(1<<j-1)][j-1];
}
}
int qum(int L,int R)
{
int k=lg[R-L+1];//快速找到长度对应的最大2次幂
return a[dp[L][k]]>=a[dp[R-(1<<k)+1][k]]?dp[L][k]:dp[R-(1<<k)+1][k];
}
void up(int pre,int &o,int l,int r,int x)
{
o=++cnt;
sum[o]=sum[pre]+1;
ls[o]=ls[pre];
rs[o]=rs[pre];
if(l==r)return ;
int m=(l+r)/2;
if(x<=m)up(ls[pre],ls[o],l,m,x);
else up(rs[pre],rs[o],m+1,r,x);
}
int qu(int pre,int o,int l,int r,int x)//区间小于等于x的数的个数
{
if(r<=x)
{
return sum[o]-sum[pre];
}
int m=(l+r)/2;
int ans=0;
ans+=qu(ls[pre],ls[o],l,m,x);
if(x>m)ans+=qu(rs[pre],rs[o],m+1,r,x);
return ans;
}
void cal(int L,int R)
{
if(L>R)return ;
if(L==R)
{
if(a[L]==1)ans++;
return ;
}
int pos=qum(L,R);
//printf(" %d %d %d\n",L,R,pos);
if(pos-L<R-pos)//左边少
{
for(int i=L;i<=pos;i++)
{
int k=a[pos]/a[i];
int kli=upper_bound(li+1,li+1+sz,k)-li;
if(kli<=1)continue;
int num=qu(rt[pos-1],rt[R],1,sz,kli-1);//pos到R之间小于kli-1的数的个数。
// printf("------ %d %d %d %d\n",i,k,kli,num);
ans+=num;
}
}
else
{
for(int i=R;i>=pos;i--)
{
int k=a[pos]/a[i];
int kli=upper_bound(li+1,li+1+sz,k)-li;
if(kli<=1)continue;
int num=qu(rt[L-1],rt[pos],1,sz,kli-1);//L到pos之间小于kli的数的个数。
//printf("++++++ %d %d %d %d\n",i,k,kli,num);
ans+=num;
}
}
cal(L,pos-1);
cal(pos+1,R);
}
int main()
{
int n;
lg[0]=-1;
for(int i=1;i<M;i++)lg[i]=lg[i>>1]+1;
cin>>n;
for(int i=1;i<=n;i++)
scanf("%d",&a[i]),li[++sz]=a[i];
RMQ(n);
sort(li+1,li+1+sz);
sz=unique(li+1,li+1+sz)-(li+1);
for(int i=1;i<=n;i++)
{
ali[i]=lower_bound(li+1,li+1+sz,a[i])-li;
up(rt[i-1],rt[i],1,sz,ali[i]);
}
/*while(1)
{
int l,r,k;
scanf("%d%d%d",&l,&r,&k);
printf("%d\n",qu(rt[l-1],rt[r],1,sz,k));
}*/
ans=0;
cal(1,n);
printf("%lld\n",ans);
return 0;
}