文章目录
202109-2 非零段划分
题目描述
输入格式
从标准输入读入数据。
输入的第一行包含一个正整数 n。
输入的第二行包含 n 个用空格分隔的自然数 A1,A2,···,An。
输出格式
输出到标准输出。
仅输出一个整数,表示对数组 A 进行操作后,其非零段个数能达到的最大值。
样例1输入
11
3 1 2 0 0 2 0 4 5 0 2
样例1输出
5
样例1解释
样例2输入
14
5 1 20 10 10 10 10 15 10 20 1 5 10 15
样例2输出
4
样例2解释
样例3输入
3
1 0 0
样例3输出
1
样例3解释
样例4输入
3
0 0 0
样例4输出
0
样例4解释
无论 p 取何值,A 都不含有非零段,故非零段个数至多为 0。
子任务
代码
#include <iostream>
#include<vector>
using namespace std;
const int N = 1e6;
int di[N], arr[N];
int n;
void add(int l, int r) {
//表示以l为线以下的数变为零的话会增加1个非零段,而以r+1为线以下为零会减少1个非零段
di[l]++;
di[r + 1]--;
}
int main()
{
cin >> n;
for (int i = 1; i <= n; i++)cin >> arr[i];
for (int i = 1; i <= n; i++) {
if (arr[i - 1] < arr[i])//读取到比上一个数大的数字
{
add(arr[i - 1] + 1, arr[i]);//计算当前的数字与前一个数字可以改变的数字段的个数
}
}
int maxn = 0;
int pre = 0;
for (int i = 1; i < 1e4; i++)
{
pre += di[i];//从1开始计算非零段个数
maxn = max(maxn, pre);
}
cout << maxn;
return 0;
}
思路
该题目用到了差分数组,什么是差分数组?
例如:
A={0,1,2,3,4,5,6,7,8,9};
B[i]=A[i]-A[i-1];
则B={0,1,1,1,1,1,1,1,1,1};
中B数组就是A的差分数组,B数组反映了A数组相邻元素之间的差值。B数组(差分数组)对某段连续的数据加上或者减去相同的数字的操作十分简便。例如:对A数组中(2,7]区间的数字都加上4,则只需在B数组的3号位加上4,并且在8号位减去4即可,改变后的B数组变为
B={0,1,1,5,1,1,1,1,1,1};
根据B数组得出来的A数组为
A={0,1,2,7,8,9,10,11,8,9};
代码中的di数组存储的是以对应位置的数字来变化所增加的非零段的个数。对读取数组进行的操作是对读取到的数据进行相邻的数据的比较,如果当前位置的数字大于前面位置的数字,则说明以前面数字为线的话非零段将会加一。(不单单如此,后面还有其他条件)
例:A={0,1,2,3,4,5,6,7,8,9};
当前位置在2号位,也就是A[2]=2,A[2]>A[1],将小于等于A[1]以下的数字变为0的话0号位和2号位之间将会产生0段,如果此时0号位是大于A [1]的数字的话非零段就会加一。如果不是大于A[1]的话,则不会加一。
所以此时还需要另一个条件,还是接着上面的例子说,当前位置为2,如果以A[2]+1作为线,也就是将小于等于A[2]的数字全变为0的话,由于前面的位置存在着比A[2]要小的数字,所以在遍历到前面的数字的时候可能存在非零段比当前要多的情况。
所以代码中的add方法就是解决这个的,如果存在当前的位置的数字比前一位数字大那么就对前一位存储的数字对应的di