Beautiful Pair

题目链接: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;
}
发布了725 篇原创文章 · 获赞 244 · 访问量 4万+

猜你喜欢

转载自blog.csdn.net/weixin_43826249/article/details/104712169