POJ 1836 Alignment

題目傳送門

題目大意:有一些士兵站成一排,一開始他們是按編號站的,但是他們的首領不喜歡這樣,於是首領讓一些人出列,剩下的人中每個人都可以看向左邊或右邊的遠方(即每個人的身高是隊列左端或右端到他的所有士兵裏唯一最高的)。輸出這些士兵的身高,求最少出列幾個人可以滿足首領的要求。

分析:解法很明確,分別求得隊列從前往後和從後往前的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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章