题目描述
给定两个长度为n的序列a, b。
你需要选择一个区间[l, r],使得al+…+ar>=0且bl+…+br>=0。最大化你选择的区间长度。
输入格式
第一行一个整数n,第二行n个整数a1~an,第三行n个整数b1~bn。
输出格式
一行一个整数表示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
", ans);
return 0;
}