问题描述
解题思路
非零段数量的计算
在数组
A
A
A的开头和结尾处各加一个
0
0
0,可以清楚地看出:每一个非零段的结尾都与0紧邻
。
非零段数量的更新
正整数
p
p
p的取值范围
为
A
1
+
1
,
A
2
+
1
,
…
…
A
n
+
1
A_1+1,A_2+1,……A_n+1
A1+1,A2+1,……An+1去重后的集合。
p
p
p取其他值的效果最终会与取上述值的效果一致。
我们将
A
1
+
1
,
A
2
+
1
,
…
…
A
n
+
1
A_1+1,A_2+1,……A_n+1
A1+1,A2+1,……An+1排序
、去重
后的结果记作:
1
≤
a
1
+
1
<
a
2
+
1
<
…
…
<
a
k
+
1
,
a
i
(
1
≤
i
≤
k
)
∈
A
1\le a_1+1<a_2+1<……<a_k+1,a_i(1\le i\le k) \in A
1≤a1+1<a2+1<……<ak+1,ai(1≤i≤k)∈A
同时,
p
p
p取
a
i
+
1
(
1
≤
i
≤
k
)
a_i+1(1\le i\le k)
ai+1(1≤i≤k)得到的非零段数量
P
e
r
i
o
d
N
u
m
i
PeriodNum_{i}
PeriodNumi可以在
p
p
p取
a
i
−
1
+
1
a_{i-1}+1
ai−1+1得到的非零段数量
P
e
r
i
o
d
N
u
m
i
−
1
PeriodNum_{i-1}
PeriodNumi−1上得到,这样可以避免重复计算
。
我们只需要在
p
p
p取
a
i
−
1
+
1
a_{i-1}+1
ai−1+1得到的数组A的基础上,将
a
i
a_i
ai依次替换为
0
0
0。并根据以下规则
(以
a
i
=
1
a_i=1
ai=1为例)由
P
e
r
i
o
d
N
u
m
i
−
1
PeriodNum_{i-1}
PeriodNumi−1得到
P
e
r
i
o
d
N
u
m
i
PeriodNum_i
PeriodNumi:
AC代码
#include <iostream>
#include <vector>
#include <set>
#include <map>
using namespace std;
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n;
cin >> n;
vector<int> A;
set<int> DiffNumList; // 用set将A中的数字去重、排序
map<int, vector<int>> NumPos; // NumPos将不同数字的位置分别记录下来
A.push_back(0); //在A开头添加一个0
for (int i = 1; i <= n; ++i)
{
int Num;
cin >> Num;
A.push_back(Num);
DiffNumList.insert(Num);
NumPos[Num].push_back(i);
}
int PeriodNum = 0;
A.push_back(0); //在A结尾添加一个0
for (int i = 1; i <= n; ++i)
{
if (A[i] != 0 && A[i + 1] == 0)
{
++PeriodNum;
}
}
int maxPeriodNum = PeriodNum;
for (int Num : DiffNumList)
{
if (Num == 0)
continue;
for (int i = 0; i < NumPos[Num].size(); ++i)
{
int beginIndex = NumPos[Num][i], endIndex = beginIndex;
if (A[beginIndex] == 0)
{
continue; // 在之前的循环中已经将连着的Num变为了0
}
while (A[endIndex] == Num) // 找到相邻的Num
{
A[endIndex] = 0;
++endIndex;
}
endIndex -= 1;
if (A[beginIndex - 1] == 0 && A[endIndex + 1] == 0)
{
--PeriodNum; // 少一个非零段
}
else if (A[beginIndex - 1] != 0 && A[endIndex + 1] != 0)
{
++PeriodNum; // 多一个非零段
}
}
maxPeriodNum = max(PeriodNum, maxPeriodNum);
}
cout << maxPeriodNum << endl;
return 0;
}