[ABC282Ex] Min + Sum 题解

考虑对于每一个 \(A_i\),找到左边第一个小于和右边第一个不大于该值的数的下标 \(L_i,R_i\),那么 \(A_i\) 就是所有满足 \(L_i<l\le i\le r<R_i\) 的区间 \([l,r]\) 的最小值。

如果 \(i-L_i<R_i-i\) 则枚举 \(l\),否则枚举 \(r\),再二分找到满足要求的另一个端点的区间即可。

代码:

#include<bits/stdc++.h>
#define ll long long
#define mxn 200003
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define rept(i,a,b) for(int i=a;i<b;++i)
#define drep(i,a,b) for(int i=a;i>=b;--i)
using namespace std;
int n,tot,q[mxn],l[mxn],r[mxn],rt[mxn];
ll s,mx,ans,a[mxn],b[mxn];
signed main(){
	scanf("%d%lld",&n,&s);
	rep(i,1,n)scanf("%lld",&a[i]);
	rep(i,1,n)scanf("%lld",&b[i]),b[i]+=b[i-1],mx=max(mx,b[i]);
	rep(i,1,n){
		while(tot&&a[i]<a[q[tot]])tot--;
		l[i]=q[tot];
		q[++tot]=i;
	}
	tot=0,q[0]=n+1;
	drep(i,n,1){
		while(tot&&a[i]<=a[q[tot]])tot--;
		r[i]=q[tot];
		q[++tot]=i;
	}
	rep(i,1,n){
		l[i]++,r[i]--;
		if(i-l[i]<r[i]-i){
			rep(j,l[i],i)if(b[i]<=s-a[i]+b[j-1]){
				ans+=upper_bound(b+i,b+r[i]+1,s-a[i]+b[j-1])-b-i;
			}
		}else{
			rep(j,i,r[i])if(a[i]+b[j]-s<=b[i-1]){
				ans+=i-(lower_bound(b+l[i]-1,b+i,a[i]+b[j]-s)-b);
			}
		}
	}
	cout<<ans;
	return 0;
}
posted @ 2023-04-22 10:33  zifanwang  阅读(9)  评论(0编辑  收藏  举报  来源