首先把输入的序列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;
}

京公网安备 11010502036488号