题目描述:
LB有n列火车。
火车按照序号从1~n排列在入口轨道上(1号火车在最前方,即下图入口最右方),火车的行进方向都是从左至右。
有钱的LB想在入口与出口之间修建k条中部轨道,火车可从入口轨道进入任意一条中部轨道,最后都从出口轨道驶出。
LB想让火车按照价格递增的顺序驶出,便找到JZL,问至少要修建多少条中部轨道,可是JZL天生愚钝,你能帮他解决这个问题吗?
注:下图中的数字是价格而不是序号。
输入描述:
第一行输入一个整数n,表示火车的数量。
接下来n行,每行一个整数,第i+1行表示第i列火车的价格ai。
0<n<=1e5
0<ai<=1e5,且ai互不相等
输出描述:
输出一个整数k。
输入样例:
9
8
4
2
5
3
9
1
6
7
输出样例:
4
核心思想:
- 进入相同中部轨道的火车,前后顺序不会改变;
- 进入不同中部轨道的火车,前后顺序可能改变。
由1可知:任意一条中部轨道上的火车,进入中部轨道的顺序应当是上升子序列,如下图,(第一条中部轨道8在前,9在后)
输入数组为8 4 2 5 3 9 1 6 7 (8在前,9在后)
四条中部轨道对应如下四条上升子序列
8 9
4 5 6 7
2 3
1
此题转换为求输入数组至少可以分为多少个上升子序列,
即求输入数组的最长下降子序列的长度。
采用贪心的方式求最长下降子序列的图解:
上图每一列是一个上升子序列,
最下面一行8 4 2 1就是一个最长下降子序列
上图的列数就是最长下降子序列的长度cnt,也是代码中数组b的长度。
代码如下:
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
const int N=1e5+50;
int a[N],b[N];
bool cmp(int x,int y){ return x>y;}
int main()
{
int n,cnt=0;
cin>>n;
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
for(int i=1;i<=n;i++){
//贪心找到数组b中第一个小于a[i]的位置
int pos=lower_bound(b,b+cnt,a[i],cmp)-b;
b[pos]=a[i];
//若数组b中没有比a[i]小的数,那么lower_bound会返回cnt
if(pos==cnt) cnt++;
}
cout<<cnt<<endl;
return 0;
}