Gravatar
yrtiop
积分:2101
提交:309 / 808

Pro3687  [BJOI2016]回转寿司

考虑枚举 $r$,计算出所有满足题意的 $l$ 的数量。

设 $S$ 为 $A$ 的前缀和数组,若 $L \le S_r - S_l \le R$,则区间 $(l,r]$ 满足题意。

作一个简单的变化就能求出 $S_l$ 的范围:$S_r - R\le S_l\le S_r - L$。

那么我们依次枚举 $1\ldots N$ 作为 $r$,维护 $S_0 \ldots S_{r - 1}$ 即可。

可以使用树状数组+离散化或者动态开点权值线段树,我选择的是树状数组+离散化。

时间复杂度 $O(N\log N)$。

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 1e5 + 5;
typedef long long ll;
const int maxm = 4e5 + 5;
int n,cnt;
ll L,R,a[maxn],d[maxm],c[maxm],s[maxn];
int sum[maxm];
int lowbit(int x) {
	return x & -x;
}
void add(int x,int y) {
	if(!x)return ;
	for(;x <= cnt;x += lowbit(x))sum[x] += y;
	return ;
}
int query(int x) {
	int ans = 0;
	for(;x;x -= lowbit(x))ans += sum[x];
	return ans;
}
int main() {
	scanf("%d%lld%lld",&n,&L,&R);
	d[++ cnt] = s[0] = 0;
	for(int i = 1;i <= n;++ i) {
		scanf("%lld",&a[i]);
		s[i] = s[i - 1] + a[i];
		d[++ cnt] = s[i];
		d[++ cnt] = s[i] - L;
		d[++ cnt] = s[i] - R;
	}
	for(int i = 1;i <= cnt;++ i)c[i] = d[i];
	sort(c + 1 , c + 1 + cnt);
	cnt = unique(c + 1 , c + 1 + cnt) - c - 1;
	for(int i = 1;i <= 3 * n + 1;++ i)d[i] = lower_bound(c + 1 , c + 1 + cnt , d[i]) - c;
	add(d[1] , 1);//提前插入 s[0]
	ll ans = 0;
	for(int i = 1;i <= n;++ i) {
		ans += query((int)d[3 * i]) - query((int)d[3 * i + 1] - 1);
		add((int)d[3 * i - 1] , 1);
	}
	printf("%lld",ans);
	return 0;
}


2024-06-22 16:44:05    
我有话要说
暂无人分享评论!