问题描述
A1,A2,⋯,An 是一个由 n 个自然数(非负整数)组成的数组。我们称其中 Ai,⋯,Aj 是一个非零段,当且仅当以下条件同时满足:
- 1≤i≤j≤n;
- 对于任意的整数 k,若 i≤k≤j,则 Ak>0;
- i=1 或 Ai−1=0;
- j=n 或 Aj+1=0。
下面展示了几个简单的例子:
- A=[3,1,2,0,0,2,0,4,5,0,2] 中的 4 个非零段依次为 [3,1,2]、[2]、[4,5] 和 [2];
- A=[2,3,1,4,5] 仅有 1 个非零段;
- A=[0,0,0] 则不含非零段(即非零段个数为 0)。
现在我们可以对数组 A 进行如下操作:任选一个正整数 p,然后将 A 中所有小于 p 的数都变为 0。试选取一个合适的 p,使得数组 A 中的非零段个数达到最大。若输入的 A 所含非零段数已达最大值,可取 p=1,即不对 A 做任何修改。
输入格式
从标准输入读入数据。
输入的第一行包含一个正整数 n。
输入的第二行包含 n 个用空格分隔的自然数 A1,A2,⋯,An。
输出格式
输出到标准输出。
仅输出一个整数,表示对数组 A 进行操作后,其非零段个数能达到的最大值。
样例输入
11
3 1 2 0 0 2 0 4 5 0 2
样例输出
5
评测用例规模与规定
70% 的测试数据满足 n≤1000;
全部的测试数据满足 n≤5×105,且数组 A 中的每一个数均不超过 104。
思路
首先,由题目可得,存在一个正整数p,使得数组A经过p的处理之后得到最多的非零段。我一开始的思路是,当经过p处理修改a[i]为0后,a[i-1]和a[i+1]都等于0时非零段减一,都不等于0时非零段加一。最后记下非零段最多的时候。如果不经过其他处理这样只可以过70%的数据。
这道题其实考的是对前缀和和差分数组的性质的理解。当a[i]>a[i-1]时,当p取到这两个数之间的值时,这里会出现一个非零段,也就是非零段加1,这就需要对一个范围都加上1,这就可以用到差分数组的性质,当我们要对一个范围[l,r]的数全体加上或减去某个值n时,我们只需要对它的差分数组diff[l]+n,diff[r+1]-n;然后再求前缀和得到的数组便是进行处理之后的数组。
(对前缀和还有差分数组一点都不了解的可以去看看这位大佬的博客ycloong’s blog)
参考代码
70分代码
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
ArrayList<Integer> list = new ArrayList<Integer>();
list.add(0);
int n = scanner.nextInt();
int sum = 0,maxs = 0;
boolean f = false;
for(int i = 0;i < n;i ++) {
int t = scanner.nextInt();
list.add(t);
if(t != 0) {
if(!f) {
sum ++;
f = true;
}
}else {
f = false;
}
}
maxs =Math.max(maxs, sum);
list.add(0);
ArrayList<Integer> list2 = new ArrayList<Integer>();
for (Integer in : list) {
if (!list2.contains(in)) {
list2.add(in);
}
}
list2.sort(Comparator.naturalOrder());
for(int i : list2) {
for(int j = 1;j < n+1;j ++) {
int k =list.get(j);
if(k <= i && k != 0) {
list.set(j, 0);
int k1 = list.get(j-1),k2 = list.get(j+1);
if(k1 == 0 && k2 == 0) {
sum --;
}
else if(k1 != 0 && k2 != 0) {
sum ++;
}
}
}
maxs = Math.max(maxs, sum);
}
System.out.println(maxs);
}
100分代码
static int N = 100000;
static int []dif = new int[N];
public static void add(int l,int r) {
dif[l]++;
dif[r + 1]--;
} //对差分数组进行一整段的加减
public static void main(String[] args) {
new _0902().run();
}
public void run() {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
int []a = new int[n+1];
a[0] = 0; //数组最前面要放一个0,不然开始就会判断错误
for(int i = 1;i < n+1;i ++) {
a[i] = scanner.nextInt();
}
for (int i = 1; i < n+1; i++) {
if (a[i] > a[i-1]) {
add(a[i - 1] + 1, a[i]);
}
}
int maxn = 0, pre = 0;
for (int p = 1; p < 1e4; p++) {
pre += dif[p];
maxn = Math.max(maxn, pre);
}
System.out.println(maxn);
}
GitHub Issues