CF689D Friends and Subsequences题解

CF689D Friends and Subsequencesr题解

题意

给定两个序列,请求有多少个数对(l,r)满足在第一个序列中这个区间内的最大值等于第二个序列中这个区间内的最小值,用公式给出,就是:

\[max_{l}^{r} a = min_{l}^{r} b \]

题解

我们思考,当我们固定一个 \(l\) ,能不能快速地求出合法的 \(r\)

\(l\)固定,向后求最大和最小,min满足的一定是一个单调不增的函数,max满足的一定是个单调不减的函数,两个函数之间交叠的部分,就是我们可取的 \(r\) .

可以用二分求解出合法的 \(r\) 的起始位置和结束位置,至于快速求解出最大和最下值,用st表即可。

code

#include<iostream>
#include<cstdio>
using namespace std;
typedef long long ll;
const ll maxn=200001;
ll n,lg[maxn+1],ans;
ll a[maxn],b[maxn];
ll stMax[maxn][20];
ll stMin[maxn][20];
struct abc{
	ll left,right;
}ty;
ll searchMax(ll l,ll r){
	ll k=lg[r-l+1];
	return max(stMax[l][k],stMax[r+1-(1<<k)][k]);
}
ll searchMin(ll l,ll r){
	ll k=lg[r-l+1];
	return min(stMin[l][k],stMin[r+1-(1<<k)][k]);
}
int main(){
	scanf("%lld",&n);
	for(ll i=1;i<=n;i++){
		scanf("%lld",&a[i]);
		stMax[i][0]=a[i];
	} 
	for(ll i=1;i<=n;i++){
		scanf("%lld",&b[i]);
		stMin[i][0]=b[i];
	}
	for(ll j=1;j<20;j++){
		for(ll i=1;i+(1<<j)-1<=n;i++){
			stMax[i][j]=max(stMax[i][j-1],stMax[i+(1<<(j-1))][j-1]);
			stMin[i][j]=min(stMin[i][j-1],stMin[i+(1<<(j-1))][j-1]);
		}
	}
	for(ll i=1;i<=n;i++)
		lg[i]=lg[i-1]+((1<<lg[i-1])==i);//预处理的log数组,可以选择用cmath替代 
	for(ll i=1;i<=n;i++)
		lg[i]--;
	for(ll i=1;i<=n;i++){
		if(b[i]<a[i])
			continue;
		ty.left=-1,ty.right=-1;
		ll low=i,high=n;
		while(low<=high){//求解出合法的r的左侧 
			ll mid=(low+high)>>1;
			ll res1=searchMax(i,mid);
			ll res2=searchMin(i,mid);
			if(res1==res2){
				ty.left=mid;
				high=mid-1;
			}else if(res1>res2){
				high=mid-1;
			}
			else{
				low=mid+1;
			}
		}
		if(ty.left==-1)continue;
		low=i,high=n;
		while(low<=high){//求解出合法的r的右侧 
			ll mid=(low+high)>>1;
			ll res1=searchMax(i,mid);
			ll res2=searchMin(i,mid);
			if(res1==res2){
				ty.right=mid;
				low=mid+1;
			}else if(res1>res2){
				high=mid-1;
			}
			else{
				low=mid+1;
			}
		}
		if(ty.right==-1) continue;
		ans=ans+ty.right-ty.left+1; 
	}
	printf("%lld",ans); 
	return 0;
} 
posted @ 2021-12-02 13:02  xwl呀。  阅读(101)  评论(0)    收藏  举报