题目链接:Beautiful Pair
看到这种式子,很容易想到,分治最大值,计算两边答案。(如果想不到,只能题做少了)。
然后,我们可以用ST表预处理出区间最大值的位置。
然后对于区间最大值的位置mid,我们可以计算两边的答案,每次我们选择小的区间一边计算那么就是log的,去找另一个区间值在某个区间的个数,主席树即可。
AC代码:
#pragma GCC optimize("-Ofast","-funroll-all-loops")
#include<bits/stdc++.h>
//#define int long long
using namespace std;
const int N=1e5+10,M=N*30;
int n,a[N],up; long long res;
vector<int> v;
struct ST{
int st[N][20],lg[N];
inline void build(){
lg[0]=-1;
for(int i=1;i<=n;i++) lg[i]=lg[i>>1]+1;
for(int i=1;i<=n;i++) st[i][0]=i;
for(int j=1;j<=17;j++)
for(int i=1;i+(1<<j)-1<=n;i++)
st[i][j]=a[st[i][j-1]]>=a[st[i+(1<<(j-1))][j-1]]?st[i][j-1]:st[i+(1<<(j-1))][j-1];
}
inline int ask(int l,int r){
int t=lg[r-l+1];
return a[st[l][t]]>=a[st[r-(1<<t)+1][t]]?st[l][t]:st[r-(1<<t)+1][t];
}
}s;
struct P_seg{
int rt[N],sum[M],lc[M],rc[M],cnt;
void change(int l,int r,int &x,int y,int k){
x=++cnt; sum[x]=sum[y],lc[x]=lc[y],rc[x]=rc[y]; sum[x]++;
if(l==r) return ; int mid=l+r>>1;
if(k<=mid) change(l,mid,lc[x],lc[y],k);
else change(mid+1,r,rc[x],rc[y],k);
}
int ask(int l,int r,int x,int y,int ql,int qr){
if(ql>r||qr<l) return 0;
if(l==ql&&r==qr) return sum[x]-sum[y]; int mid=l+r>>1;
if(qr<=mid) return ask(l,mid,lc[x],lc[y],ql,qr);
else if(ql>mid) return ask(mid+1,r,rc[x],rc[y],ql,qr);
else return ask(l,mid,lc[x],lc[y],ql,mid)+ask(mid+1,r,rc[x],rc[y],mid+1,qr);
}
}p;
void solve(int l,int r){
if(l>r) return ;
if(l==r){res+=(v[a[l]-1]==1); return ;}
int mid=s.ask(l,r),mx=v[a[mid]-1];
if(mid-l+1<=r-mid){
for(int i=l;i<=mid;i++){
int k=upper_bound(v.begin(),v.end(),mx/v[a[i]-1])-v.begin();
res+=p.ask(1,up,p.rt[r],p.rt[mid-1],1,k);
}
}else{
for(int i=mid;i<=r;i++){
int k=upper_bound(v.begin(),v.end(),mx/v[a[i]-1])-v.begin();
res+=p.ask(1,up,p.rt[mid],p.rt[l-1],1,k);
}
}
solve(l,mid-1),solve(mid+1,r);
}
signed main(){
cin>>n;
for(int i=1;i<=n;i++) scanf("%d",&a[i]),v.push_back(a[i]);
s.build();
sort(v.begin(),v.end()),v.erase(unique(v.begin(),v.end()),v.end()); up=v.size();
for(int i=1;i<=n;i++) a[i]=lower_bound(v.begin(),v.end(),a[i])-v.begin()+1;
for(int i=1;i<=n;i++) p.change(1,up,p.rt[i],p.rt[i-1],a[i]);
solve(1,n);
cout<<res;
return 0;
}