```#include<bits/stdc++.h>
using namespace std;
pair<int,int> a[200100];
int n,ans=1,last=0x7fffffff;
bool flag=0;
int main() {
scanf("%d",&n);
for (int i=0; i<n; i++) scanf("%d",&a[i].first),a[i].second=i;
sort(a,a+n);//这里pair会先默认按照first排序,如果first相同再按照second排序
for (int i=0,p,pp; i<n; i++) {
p=a[i].second;
while(i+1<n && a[i+1].first==a[i].first) i++;
pp=a[i].second;
if (flag){
if (last<p) last=pp;
else ans++,last=p,flag=0;}
else {
if (last>pp) last=p;
else last=pp,flag=1;}
}
printf("%d",ans);
}
这个代码是改编自一个大佬的,对于新手(比如我)理解起来较为有难度,我个人也是花费了很多时间去理解,现在把我对这个代码的理解贴出来,希望对新手有启发,可以更快的理解这道题目,(写的不太好)
例子:360963
这一串数字,分成了好几组,每一组的数字相同,0 33 66 9
要判断的就是,后面一段的数字组合可不可以加到前一段的后面,如果可以就继续,如果不可以就再开一个数组
第一个数字0,看成是下坡,因为flag初始化是0,
然后0的这个数字的原始下标是3,第二个数字组是33 要判断33可不可以接在0后面,3的最大的下标是6,6>3
这里就不可以是下坡了,因为下坡要的是前一个数组的有边界要>pp,
这里的pp也就是33这个组合中3的最大的那个原始下标
但是这里可以不用再开一个数组,因为可以变成上坡,然后有边界改成pp,也就是33组合的最大的下标6
比如33组合中的最大的原始下标是小于0的原始下标的,那么就是先读33,再读0,这个时候因为是可以在队列的右边和左边
加元素的,所以可以把0加到33这个组合的右边
但是现在33组合中的最大的下标是6,是大于0的原始下标3的,所以现在就得变成上坡的,也就是下一个组,也就是66组的
最小的原始下标要大于更新过的右边界,也就是6,不然就不可以加到这个队列里,就要另外开一个
为什么呢??
就比如66组的最小下标是小于更新后的last也就是6的,那么就代表有一个6是在两个3之间
或者在最小的原始下标3的后面的,
假设可以把这个66加到这个队列里来那么读完3之后就要读6,那么下一个0和9就不可以读了然后再读一个6,再读一个3
第一个队列3366 然后还要另外加两个队列,放0和9,这样就是三个了,但是最优解是两个。
但是如果是满足66组最小的原始小标大于更新后的last的话
也就是说,66在33的后面,那完全可以033后面直接加66->03366
总上来看,题目中的例子就是要再分一个队列的,此时的flag是又变成0了,新的队列中的last是6的最小原始下标
接下来的9组的下标是什么样都可以了因为这个是最后一个元素了,
假设不是最后一个
9的下标是大于last的,这里的last是66组中6最小的原始下标,那么这个时候就类似与上面的33的最大下标大于0的位置一样
last变成9组中最大的原始下标,(这里因为9只有一个,所以就是9的原始下标)这个时候,又变成上坡了,后面的
组合的最小的原始下标要大于这个last,不然就再开一个队列,然后变成下坡