首先把输入的序列dat[1...n] 映射成 序列id[1...n];
序列id[i]表示 原数组中第i个数是第id[i]大的数;
(特别地,如果原序列中两个数相等,那么按原数组下标从小到大排序)

题意即可转化为:从1..n扫描id序列。每次找出一段长度最小的区间,使得区间下标[i,j]里的值在id[i...j]出现且仅出现一次。求找到区间的个数。

#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;

const int maxN = 1e6+10 ;
const int INF = 33333333 ;

struct Dat
{
    int v;
    int idx;
}dat[maxN];
int n;
int id[maxN];
int ans;

bool cmp(Dat a,Dat b)
{
    if(a.v<b.v)return a.v<b.v;
    else if(a.v==b.v)return a.idx<b.idx;
    return 0;
}

int main()
{
    cin>>n;

    for(int i =1;i<=n;i++)
    {
        int x;scanf("%d",&x);
        dat[i].v = x;
        dat[i].idx = i;
    }

    sort(dat+1,dat+n+1,cmp);

    for(int i =1;i<=n;i++)id[dat[i].idx] = i;  

    int l = 1;                 //扫描时当前区间的左端点。
    int minv = INF,maxv = 0;
    for(int i =1;i<=n;i++)
    {
        minv = min(minv,id[i]);
        maxv = max(maxv,id[i]);
        if(maxv == i&&minv == l)
        {
            ans++;
            l = i+1;
            minv = INF;
            maxv = 0;
        }
    }
    cout<<ans<<endl;
    return 0;
}