序列

题目描述

给定两个长度为n的序列a, b。

你需要选择一个区间[l, r],使得al+…+ar>=0且bl+…+br>=0。最大化你选择的区间长度。

输入格式

第一行一个整数n,第二行n个整数a1an,第三行n个整数b1bn。

输出格式

一行一个整数表示max(r-l+1)。保证至少有一个区间满足条件。

样例

样例输入

5
2 -4 1 2 -2
-2 3 1 -3 1

样例输出

1

数据范围与提示

对于20% 的数据,n<=5000。

对于60% 的数据,n<=10^5。

对于100% 的数据,1<=n<=10^6,|ai|, |bi|<=10^9。 数据有一定梯度。

简单解释

理解题意,我们发现一个合法的区间要满足以下条件:

\[l \leq r \]

\[sumA[l] \leq sumA[r] \]

\[sumB[l] \leq sumB[r] \]

\(sum\) 为前缀和。然后玩意儿这一看就是个三维偏序,然后CDQ搞它就完了

其实这题并不用CDQ分治,不要想太多...当然你非要用也不拦你。

所以,先按 \(sumA\) 从小到大排一下序,这样我们在枚举的时候自然就满足了第二个条件。

排完序,从1开始枚举,显然每个 \(i\) 会有一个对应的 \(sumb\),然后我们就需要在小于这个\(sumb\)\(sumb\)中找到一个最小的下标 \(l\),看这个 \(l\)\(i\) 是否满足 \(l \leq i\),如果是,更新答案。

以上操作显然要用数据结构来维护,所以上树状数组。(不要线段树,T飞)

显然树是对\(sumb\)来开的,而\(sumb\)有点大,所以离散化一下。

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e6 + 10;
char buf[1 << 20], *p1 = buf, *p2 = buf;
char getc() {
	if(p1 == p2) {
		p1 = buf, p2 = buf + fread(buf, 1, 1 << 20, stdin);
		if(p1 == p2) return EOF; 
	}
	return *p1++;
}
int read() {
	int s = 0, w = 1;
	char c = getc();
	while(c < '0' || c > '9') {if(c == '-') w = -1; c = getc();}
	while(c >= '0' && c <= '9') s = s * 10 + c - '0', c = getc();
	return s * w;
}

int n;

struct NODE {
	long long a, b;
	int id;
}Index[maxn];

bool CMP(NODE x, NODE y) {return x.a < y.a;}

int w[maxn << 2];

void Change(int x, int val) {
	for(; x <= n; x += (x & -x)) w[x] = min(w[x], val);
}

long long Ask(int x) {
	int ans = INT_MAX;
	for(; x; x -= (x & -x)) ans = (ans < w[x] ? ans : w[x]);
	return ans;
}

long long sum1[maxn], sum2[maxn];

int main() {
	freopen("B.in", "r", stdin);
	freopen("B.out", "w", stdout);
	n = read();
	for(int i = 1; i <= n; i++) {
		sum1[i] = read() + sum1[i - 1];
		Index[i].a = sum1[i];
		Index[i].id = i;	
	}
	for(int i = 1; i <= n; i++) {
		sum2[i] = read() + sum2[i - 1];
		Index[i].b = sum2[i];
	}
	
	long long ans = 1;
	for(int i = 1; i <= n; i++) 
		if(sum1[i] >= 0 && sum2[i] >= 0) ans = (ans > i ? ans : i);
		
	sort(Index + 1, Index + 1 + n, CMP);
	sort(sum2 + 1, sum2 + 1 + n);
	int len = unique(sum2 + 1, sum2 + 1 + n) - sum2 - 1;
	
	memset(w, 0x3f, sizeof w);
	for(int i = 1; i <= n; i++) {
		int p = lower_bound(sum2 + 1, sum2 + 1 + len, Index[i].b) - sum2;
		Change(p, Index[i].id);
		ans = max(ans, Index[i].id - Ask(p));
	}
	printf("%lld\n", ans);
	return 0;
}

posted @ 2020-09-09 10:40  zfio  阅读(206)  评论(0编辑  收藏  举报