題目:傳送門
題目大意:有一些士兵站成一排,一開始他們是按編號站的,但是他們的首領不喜歡這樣,於是首領讓一些人出列,剩下的人中每個人都可以看向左邊或右邊的遠方(即每個人的身高是隊列左端或右端到他的所有士兵裏唯一最高的)。輸出這些士兵的身高,求最少出列幾個人可以滿足首領的要求。
分析:解法很明確,分別求得隊列從前往後和從後往前的LIS,然後再枚舉身高最高分別出現的位置,以求得調整後隊列的最大人數_max,則ans=n-_max。首先,求LIS有O(nlogn)的算法,具體參見文章,這個算法實際是保存了各種長度LIS的最末尾元素,以便後續對LIS做出調整,這裏可以使用單調棧來維護,用筆寫寫過程能更好的理解這個算法的思想。還有就是注意二分查找的寫法了,細節非常多,關於各種二分的寫法,分享一篇文章吧。最後再講一個細節,那就是位運算<<和>>的運算優先級是比+、-都低的,在使用的時候應該注意。
代碼:
#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstring>
using namespace std;
const int MAXN=1005;
double h[MAXN];
int l[MAXN];
int r[MAXN];
double lstk[MAXN];
double rstk[MAXN];
int n;
void solve(){
int _max;
int ltop=0,rtop=0;
lstk[ltop]=rstk[rtop]=0.0;
for(int i=0;i<n;++i){
if(h[i]>lstk[ltop]){
lstk[++ltop]=h[i];
}
else{
int lb=1,rb=ltop,m;
while(lb<rb){
m=lb+(rb-lb)/2;
if(lstk[m]<h[i]) lb=m+1;
else rb=m;
}
lstk[rb]=h[i];
}
l[i]=ltop;
}
for(int i=n-1;i>=0;--i){
if(h[i]>rstk[rtop]){
rstk[++rtop]=h[i];
}
else{
int lb=1,rb=rtop,m;
while(lb<rb){
m=lb+(rb-lb)/2;
if(rstk[m]<h[i]) lb=m+1;
else rb=m;
}
rstk[rb]=h[i];
}
r[i]=rtop;
}
_max=max(l[n-1],r[0]);
for(int i=0;i<n;++i){
for(int j=i+1;j<n;++j){
_max=max(_max,l[i]+r[j]);
}
}
cout<<n-_max<<endl;
}
int main(){
ios::sync_with_stdio(false);
cin>>n;
for(int i=0;i<n;++i){
cin>>h[i];
}
solve();
return 0;
}