小欧的数组构造
[题目链接](https://www.nowcoder.com/practice/7e86d90777ad41e4a59d2e937bf9afc2)
思路
已知长度为 的数组
,其中
,要求构造长度为
的整数数组
,使
中正数个数最多。
决定一切
一旦确定了 的值,整个数组就被唯一确定了:
,
,依此类推。展开后可以发现:
$$
其中 ,
。也就是说,
关于
是线性的,且系数在
和
之间交替。
转化为不等式计数
要让 (正数),分两种情况:
- 偶数下标
:
,即
(因为
是整数)
- 奇数下标
:
,即
注意偶数下标希望 尽量大,奇数下标希望
尽量小,两者互相矛盾。我们要找一个整数
,使满足的不等式总数最多。
扫描线求解
把每个约束看成数轴上的一个事件:
- 偶数下标
:在
处放一个
事件——当
达到这个值时,多满足一个约束
- 奇数下标
:在
处放一个
事件——当
达到这个值时,少满足一个约束
初始时(),所有偶数约束都不满足,所有奇数约束都满足,所以初始得分 = 奇数下标的个数。
将所有事件按坐标排序,从左到右扫描并累加 delta,过程中维护得分的最大值即为答案。
样例验证
,
,
。
事件列表:
(偶):
(奇):
(偶):
排序后:、
、
。初始得分 = 1。
:得分 =
:得分 =
最大得分 = 2,与答案一致。对应 时
(2 个正数)。
代码
#include <bits/stdc++.h>
using namespace std;
int main() {
int n;
scanf("%d", &n);
vector<long long> b(n - 1);
for (int i = 0; i < n - 1; i++) scanf("%lld", &b[i]);
vector<long long> c(n);
c[0] = 0;
for (int i = 0; i < n - 1; i++) c[i + 1] = b[i] - c[i];
int countOdd = 0;
vector<pair<long long, int>> events;
for (int i = 0; i < n; i++) {
if (i % 2 == 0) {
events.push_back({-c[i] + 1, +1});
} else {
events.push_back({c[i], -1});
countOdd++;
}
}
sort(events.begin(), events.end());
int score = countOdd, best = score;
int idx = 0;
while (idx < (int)events.size()) {
long long val = events[idx].first;
int delta = 0;
while (idx < (int)events.size() && events[idx].first == val) {
delta += events[idx].second;
idx++;
}
score += delta;
best = max(best, score);
}
printf("%d\n", best);
return 0;
}
import java.util.*;
import java.io.*;
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int n = Integer.parseInt(br.readLine().trim());
StringTokenizer st = new StringTokenizer(br.readLine().trim());
long[] b = new long[n - 1];
for (int i = 0; i < n - 1; i++) b[i] = Long.parseLong(st.nextToken());
long[] c = new long[n];
c[0] = 0;
for (int i = 0; i < n - 1; i++) c[i + 1] = b[i] - c[i];
int countOdd = 0;
long[][] events = new long[n][2];
for (int i = 0; i < n; i++) {
if (i % 2 == 0) {
events[i][0] = -c[i] + 1;
events[i][1] = 1;
} else {
events[i][0] = c[i];
events[i][1] = -1;
countOdd++;
}
}
Arrays.sort(events, (a, bb) -> Long.compare(a[0], bb[0]));
int score = countOdd, best = score;
int idx = 0;
while (idx < n) {
long val = events[idx][0];
int delta = 0;
while (idx < n && events[idx][0] == val) {
delta += (int) events[idx][1];
idx++;
}
score += delta;
best = Math.max(best, score);
}
System.out.println(best);
}
}
复杂度分析
- 时间复杂度:
,瓶颈在于对事件排序。
- 空间复杂度:
,存储
数组和事件数组。

京公网安备 11010502036488号