ccfcsp 202109-2 非零段划分,差分
题目描述
算法求解
分析
利用差分的思想,每当遇到一个 a[i] < a[i+1]
的时候,就将对应的对于 p = a[i-1] + 1
到a[i]
这个区间内的所有p
的非零划分的数量+1(这就转换到了差分的思路)
然后使用前缀和统计p所有可能的取值对应的非零段的数量,去最大值即可
注意这里只需要统计上升段(或者只统计下降段也可以)
代码
只统计上升段
#include<iostream>
#include<cstdio>
#include<vector>
using namespace std;
const int N = 500010;
int di_max;
vector<int> peeks; // 所有峰值点
int a[N];
int b[N];
int n;
void add(int l, int r)
{
b[l] += 1;
b[r+1] -= 1;
}
int main()
{
// 使用差分的思路
scanf("%d", &n);
for(int i = 1; i <= n; i++) scanf("%d", &a[i]);
int maxa = 0;
for(int i = 1; i <= n; i++)
{
if(a[i-1] < a[i])
{
add(a[i-1] + 1, a[i]); // 对于 p = a[i-1] + 1 到 a[i] 这个区间内的所有p,其非零段的数量都+1
}
if(maxa < a[i]) maxa = a[i];
}
int res = 0;
for(int i = 1; i <= maxa; i++)
{
b[i] += b[i-1];
res = max(res, b[i]);
}
cout << res << endl;
return 0;
/*暴力60
scanf("%d", &n);
int maxx = 0;
for(int i = 1; i <= n; i++)
{
scanf("%d", &a[i]);
if(a[i] > maxx) maxx = a[i];
}
int res = 0;
for(int p = 1; p <= maxx; p++)
{
// 小于p的都视为0
int cnt = 0; //段数
int i = 0;
while(i <= n)
{
while(a[i] < p) i++; // p段
if(i > n) break;
while(a[i] >= p) i++;
cnt++; // 非p段
}
// cout << cnt << endl;
res = max(res, cnt);
}
cout << res;
return 0;
*/
/* 得分为0
for(int i = 1; i <= n; i++)
{
if(a[i] > a[i-1] && a[i] > a[i+1]) peeks.push_back(a[i]);
if(a[i] <= a[i-1] && a[i] <= a[i+1])
{
if (a[i] > di_max)
di_max = a[i];
}
}
int res = 0;
for(auto t : peeks)
{
if(t > di_max) res++;
}
cout << res;
return 0;
*/
}
只统计下降段
#include<iostream>
#include<cstdio>
#include<vector>
using namespace std;
const int N = 500010;
int di_max;
vector<int> peeks; // 所有峰值点
int a[N];
int b[N];
int n;
void add(int l, int r)
{
b[l] += 1;
b[r+1] -= 1;
}
int main()
{
// 使用差分的思路
scanf("%d", &n);
for(int i = 1; i <= n; i++) scanf("%d", &a[i]);
int maxa = 0;
for(int i = 0; i <= n; i++)
{
if(a[i] > a[i+1])
{
add(a[i+1] + 1, a[i]);
}
if(maxa < a[i]) maxa = a[i];
}
int res = 0;
for(int i = 1; i <= maxa; i++)
{
b[i] += b[i-1];
res = max(res, b[i]);
}
cout << res << endl;
return 0;
}
时间复杂度
\(O(n)\)