1. 程式人生 > >BZOJ 2457: [BeiJing2011]雙端隊列

BZOJ 2457: [BeiJing2011]雙端隊列

貪心 sta gre submit algorithm data discus 相同 兩個

2457: [BeiJing2011]雙端隊列

Time Limit: 10 Sec Memory Limit: 128 MB
Submit: 338 Solved: 165
[Submit][Status][Discuss]

Description

Sherry現在碰到了一個棘手的問題,有N個整數需要排序。 Sherry手頭能用的工具就是若幹個雙端隊列。 她需要依次處理這N個數,對於每個數,Sherry能做以下兩件事: 1.新建一個雙端隊列,並將當前數作為這個隊列中的唯一的數; 2.將當前數放入已有的隊列的頭之前或者尾之後。 對所有的數處理完成之後,Sherry將這些隊列排序後就可以得到一個非降的序列。

Input

第一行包含一個整數N,表示整數的個數。接下來的N行每行包含一個整數Di,其中Di表示所需處理的整數。

Output

其中只包含一行,為Sherry最少需要的雙端隊列數。

Sample Input


6
3
6
0
9
6
3

Sample Output


2

HINT

100%的數據中N≤200000。

題解:

  這個題目我們首先註意到題目所給的一個性質,就是要求兩個有序,即每個雙端隊列內部還要有有序,所以對於一個序列,我們排序一下,那麽每個雙端隊列一定取的是一個連續的區間。

  所以我們以權值為第一關鍵字,編號為第二關鍵子排序,之後模擬反的過程,如果要一個雙端隊列和法,那麽他們所取的編號一定是先下降然後上升的,這樣我們貪心,每次的元素盡量放到一個雙端隊列裏,模擬一遍就可以了。(註意,如果元素相同,那麽他們顯然是可以放在一個隊列,所以一起處理就可以了)。

代碼:

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <iostream>
#define MAXN 200100
using namespace std;
struct node{
    int v,ps;
}a[MAXN*2];
int n;
int mx[MAXN],mi[MAXN],cnt=0;
int ans=0,flag=1
,now=1<<30; bool cmp(const node A,const node B){return A.v<B.v||(A.v==B.v&&A.ps<B.ps);} int main() { scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&a[i].v),a[i].ps=i; sort(a+1,a+n+1,cmp); for(int i=1;i<=n;i++){ if(i==1||a[i].v!=a[i-1].v){ mx[cnt]=a[i-1].ps; mi[++cnt]=a[i].ps; } } mx[cnt]=a[n].ps; for(int i=1;i<=cnt;i++){ if(flag==0){ if(now>mx[i]) now=mi[i]; else now=mx[i],flag=1; } else{ if(now<mi[i]) now=mx[i]; else flag=0,now=mi[i],ans++; } } printf("%d\n",ans); return 0; }

BZOJ 2457: [BeiJing2011]雙端隊列