非零段划分
/* CCF202109-2 非零段划分 索引法 */
#include <bits/stdc++.h>
using namespace std;
const int N = 500000;//全部的测试数据满足 n≤5×10^5
const int M = 10000;//数组 A 中的每一个数均不超过 10000
int book[N + 2];//数组book[]用来标记a[i]是否置为0(全部的测试),若book[i]=1则表示a[i]被置为0
vector<int> v[M + 1];//向量数组,存放各种值所在的位置 (数组 A 中的每一个数)
int main()
{
int n, maxa = 0;
cin>>n;
int a[n+1]={0};
for (int i = 1; i <= n; i++) {//注意下标位置从一开始
cin>>a[i];
maxa = max(maxa, a[i]);
v[a[i]].push_back(i);//表示a[i]为第几个
}
int ans = 0;
if (v[0].size() != n) {//如果不是全零段的话
memset(book, 0, sizeof book);//memset函数初始化
book[0] = book[n + 1] = 1;//注意数组段前后均要置零,即一开始认为整个数组为一个整体,一个整数段
int last = 1;//变量last表示上一次的划分数,初始为一整个数段
for (int p = 0; p <= maxa; p++)
if (v[p].size() != 0) {
int t = last;//变量t表示在上一次划分的基础上,再进行p变换后的划分数。
for (int ix = 0; ix < (int)v[p].size(); ix++) {
book[v[p][ix]] = 1;//小于p置零操作,这里直接考虑小于等于,因为没什么差别
if (book[v[p][ix] - 1] && book[v[p][ix] + 1]) t--;//如果a[i]位置置为0,那么如果原先a[i-1]=0并且a[i+1]=0则划分段数减一
else if (book[v[p][ix] - 1] == 0 && book[v[p][ix] + 1] == 0) t++;//如果a[i]位置置为0,那么如果原先a[i-1]<>0并且a[i+1]<>0则划分段数加一;其他情况则段数不变
}
ans = max(ans, max(last, t));//比较得出最大值
last = t;
}
}
cout<<ans<<endl;//输出
return 0;
}