**题目描述
合唱队的N名学生站成一排且从左到右编号为1到N,其中编号为i的学生身高为Hi。现在将这些学生分成若干组(同一组的学生编号连续),并让每组学生从左到右按身高从低到高进行排列,使得最后所有学生同样满足从左到右身高从低到高(中间位置可以等高),那么最多能将这些学生分成多少组?**
输入
第一行包含一个整数N,1≤N≤105。
第二行包含N个空格隔开的整数H1到HN,1≤Hi≤109。
输出
输出能分成的最多组数。**
自我解析
对于这个题目,我第一眼也没看懂,在网上看到许多解析以及对于答案的解法,先附上答案解法
#include <bits/stdc++.h>
#define N 100007
using namespace std;
int n,a[N],b[N];
int find(int l,int r,int x){
int res=r+1;
while(l<=r){
int mid=(l+r)>>1;
if(b[mid]>=x)res=mid,r=mid-1;
else l=mid+1;
}
return res;
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;++i)scanf("%d",&a[i]);
b[n]=a[n];
for(int i=n-1;i;--i)b[i]=min(a[i],b[i+1]);
int ans=0;
for(int i=1,j=1;i<=n;++i){
if(i==j)++ans;
j=max(j,find(i+1,n,a[i]));
cout<<j<<endl;
}
printf("%d",ans);
//}
}
本题思路
先求出每个点的右边最大值,站队是由低到高,所以这个分组中的最大值一定小于右边剩余队列的最小值。
利用B[I]由后向前进行遍历,每个值存储的就是i到最后n的最小值。
构造find函数进行对比,他这里最巧妙的是没有对于左边最大值的求解,而是利用j来保存对于a[i]在那个地方是小于右边最小值的,然后在对于遍历中刷新j的大小,来确定这个组中的最大值所对应的右边的最小值。
5 3 6 9
从5开始第一次返回j就是3因为到第3个的最小值是6
第二次返回的还是3
第三次当i=3的时候为6这时候j和i相等了所以这两个一组。
然后6的时候就是返回4,到4的时候就又加1,6自己一组
最后一个最后一组
所以最后是3组
特殊情况是所有数值都是所有的数值都找到的最小值是最后一个比如
5 2 1
这时候 int res =r+1,就是为了防止这种情况。
这时候j = 4;因为是++i 所以 可以到4