CF1156E Special Segments of Permutation 和 LG4755 Beautiful Pair

CF1156E Special Segments of Permutation

给定一个长度为\(n\)的排列\(p\),求有多少区间\([l,r]\)满足,\(p_l+p_r=\max_{l\leq i\leq r}\{p_i\}\)

\(n\leq 2\times 10^5\)

题解

先预处理出每个 \(i\) 左边第一个大于它的位置(记为 \(L[i]\) )和右边第一个大于它的位置(记为 \(R[i]\) )。显然可以单调栈 \(O(n)\) 求出。

枚举最大值的位置,那么左端点只会落在 \((L[i],i)\) ,右端点只会落在 \((i,R[i])\)

那么在小的那个区间中枚举一个端点,在另外那个区间中查有没有对应的值。

这样子看上去是 \(O(n^2)\) 的,实际上是 \(O(n\log n)\) 的。

它的本质是在笛卡尔树上启发式分裂。(虽然并没有建出笛卡尔树来)

CO int N=2e5+10;
int a[N],ia[N];
int stk[N],L[N],R[N];

int main(){
	int n=read<int>();
	for(int i=1;i<=n;++i) ia[read(a[i])]=i;
	int top=0;
	for(int i=1;i<=n;++i){
		while(top and a[stk[top]]<a[i]) --top;
		L[i]=stk[top],stk[++top]=i;
	}
	stk[top=0]=n+1;
	for(int i=n;i>=1;--i){
		while(top and a[stk[top]]<a[i]) --top;
		R[i]=stk[top],stk[++top]=i;
	}
	int ans=0;
	for(int i=1;i<=n;++i){
		if(i-L[i]<R[i]-i){
			for(int j=L[i]+1;j<i;++j){
				int p=ia[a[i]-a[j]];
				ans+=i<p and p<R[i];
			}
		}
		else{
			for(int j=i+1;j<R[i];++j){
				int p=ia[a[i]-a[j]];
				ans+=L[i]<p and p<i;
			}
		}
	}
	printf("%d\n",ans);
	return 0;
}

LG4755 Beautiful Pair

小D有个数列\(\{a\}\),当一个数对\((i,j)(i\le j)\)满足\(a_i\)\(a_j\)的积不大于\(a_i,a_{i+1},\cdots,a_j\)中的最大值时,小D认为这个数对是美丽的.请你求出美丽的数对的数量。

\(1\le n\le{10}^5,1\le a_i\le{10}^9\)

题解

跟上一道题差不多,只不过细节多了很多。上一道题隐含条件\(l<r\),这题就没有了。

具体细节见代码,我好像就是凭直觉瞎改了一下就过了。

#include<bits/stdc++.h>
#include<ext/pb_ds/assoc_container.hpp>
#include<ext/pb_ds/tree_policy.hpp>
#define pbds __gnu_pbds
using namespace std;

#define CO const
#define IN inline
typedef long long int64;
typedef pbds::tree<std::pair<int,int>,pbds::null_type,std::less<std::pair<int,int> >,pbds::rb_tree_tag,pbds::tree_order_statistics_node_update> tree;

template<class T> IN T read(){
	T x=0,w=1;char c=getchar();
	for(;!isdigit(c);c=getchar())if(c=='-') w=-w;
	for(;isdigit(c);c=getchar()) x=x*10+c-'0';
	return x*w;
}
template<class T> IN T read(T&x){
	return x=read<T>();
}

CO int N=1e5+10;
int n,a[N];
int stk[N],L[N],R[N];
vector<int> que[N];
tree sum;

int main(){
	read(n);
	for(int i=1;i<=n;++i) read(a[i]);
	int top=0;
	for(int i=1;i<=n;++i){
		while(top and a[stk[top]]<a[i]) --top; // left <
		L[i]=stk[top],stk[++top]=i;
	}
	stk[top=0]=n+1;
	for(int i=n;i>=1;--i){
		while(top and a[stk[top]]<=a[i]) --top; // right <=
		R[i]=stk[top],stk[++top]=i;
	}
	for(int i=1;i<=n;++i){
		if(i-L[i]<R[i]-i){
			for(int j=L[i]+1;j<=i;++j){
				que[R[i]-1].push_back(a[i]/a[j]);
				que[i-1].push_back(-(a[i]/a[j]));
			}
		}
		else{
			for(int j=i;j<R[i];++j){
				que[i].push_back(a[i]/a[j]);
				que[L[i]].push_back(-(a[i]/a[j]));
			}
		}
	}
	int64 ans=0;
	for(int i=1;i<=n;++i){
		sum.insert({a[i],i});
		for(int x:que[i]){
			if(x>0) ans+=sum.order_of_key({x+1,0});
			else ans-=sum.order_of_key({-x+1,0});
		}
	}
	printf("%lld\n",ans);
	return 0;
}

猜你喜欢

转载自www.cnblogs.com/autoint/p/12676469.html
今日推荐