[BJOI2016] 回转寿司

前言

不是很懂,这题在洛谷上竟然是紫的。

题目

洛谷

讲解

很多做法啊,离散化树状数组,主席树,cdq 都行,我这里是常数较小的 cdq 做法。

是在没啥好讲的,做个前缀和,直接 cdq分治 + two-pointer 就做完了,注意边界问题。

用归并排序减小 cdq 常数是常见做法。

代码

写丑了。
//12252024832524
#include <bits/stdc++.h>
#define TT template<typename T>
using namespace std; 

typedef long long LL;
const int MAXN = 100005;
int n,L,R;
LL pre[MAXN],ans;

LL Read()
{
	LL x = 0,f = 1;char c = getchar();
	while(c > '9' || c < '0'){if(c == '-')f = -1;c = getchar();}
	while(c >= '0' && c <= '9'){x = (x*10) + (c^48);c = getchar();}
	return x * f;
}
TT void Put1(T x)
{
	if(x > 9) Put1(x/10);
	putchar(x%10^48);
}
TT void Put(T x,char c = -1)
{
	if(x < 0) putchar('-'),x = -x;
	Put1(x); if(c >= 0) putchar(c);
}
TT T Max(T x,T y){return x > y ? x : y;}
TT T Min(T x,T y){return x < y ? x : y;}
TT T Abs(T x){return x < 0 ? -x : x;}

LL tmp[MAXN];
void cdq(int l,int r){
	if(l == r) return;
	int mid = (l+r) >> 1,ql = l,qr = l-1;
	cdq(l,mid); cdq(mid+1,r);
	for(int i = mid+1;i <= r;++ i){
		while(ql < mid && pre[i] - pre[ql] > R) ++ql;
		while(qr < mid && pre[i] - pre[qr+1] >= L) ++qr;
		if(ql <= mid && qr <= mid && pre[i] - pre[ql] <= R && pre[i] - pre[qr] >= L) ans += qr-ql+1;
	}
	int i = l,j = mid+1,k = l;
	while(i <= mid && j <= r){
		if(pre[i] <= pre[j]) tmp[k++] = pre[i++];
		else tmp[k++] = pre[j++];
	}
	while(i <= mid) tmp[k++] = pre[i++];
	while(j <= r) tmp[k++] = pre[j++];
	for(int p = l;p <= r;++ p) pre[p] = tmp[p];
}

int main()
{
//	freopen(".in","r",stdin);
//	freopen(".out","w",stdout);
	n = Read(); L = Read(); R = Read();
	for(int i = 1;i <= n;++ i) pre[i] = pre[i-1] + Read();
	cdq(0,n);
	Put(ans,'\n');
	return 0;
}
posted @ 2022-04-06 11:52  皮皮刘  阅读(88)  评论(2编辑  收藏  举报