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

BZOJ 2457 [BeiJing2011] 雙端隊列

++ std http lin n) 不同 新建 元素 class

2457: [BeiJing2011]雙端隊列

Time Limit: 10 Sec Memory Limit: 128 MB
Submit: 340 Solved: 167
[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。

[Submit][Status][Discuss]

題解:

  此題手玩了很久,發現了一個對於不重復的元素可行的nlogn的方法。首先給每一個元素編號1~n,然後放在結構體裏面sort。例如樣例:

IN:6 1 8 7 4 2 6 OUT:3

  序號變成了1 5 4 6 3 2。可以發現首先對於1號,左右都沒有已經加入隊列的元素,那麽新建一個ans=1。對於2,新建一個ans=2。對於3,右邊有2了,就把3加入到2,ans=2。對於4,新建一個,ans=3。對於5加入到1和4都可以,對於6,加入到4和3都可以。這個可以使用並查集輕松實現。但是題目中的是有重復的。

  我們想,對於排好序的元素,每一個單調隊列一定都是從中截取連續的一段作為自己的元素的,那麽我們觀察一下他的序號。例如樣例,第一個隊列中元素的序號為3 1 6,第二個為5 2 4。題目要求依次考慮,那麽初始的元素必定序號最小,然後它左右兩邊的序號都要比它大,所以這是一個元素單調,元素的序號呈中間小,兩邊大的單調隊列。特別的,序號遞增或遞減(左邊沒有元素或右邊沒有元素)。那麽怎麽求呢?

  第一種不重復元素的方法遇到重復的元素就沒有辦法了,但是發現了序號的規律之後,我們對於重復的元素,就可以合並了,然後記下相同元素所對應的序號最大與序號最小值即可。當前面一個元素(合並之後,元素是無相同的了)是遞增的,那麽當前這一個元素如果沒有辦法繼續遞增,就要新建一個單調隊列了。前面元素遞減同理。

  不存在一種情況使得相同的元素在不同的單調隊列。因為隊列起始元素自然遞減更優,限制遞減狀態改為遞增的是最小值,把相同元素放在不同的隊列,並不能把最小的放過去,還不如放在一起。

 1 #include<queue>
 2 #include<cstdio>
 3 #include<vector>
 4 #include<cstring>
 5 #include<iostream>
 6 #include<algorithm>
 7 #define RG register
 8 #define LL long long
 9 #define fre(a) freopen(a".in","r",stdin);//freopen(a".out","w",stdout);
10 using namespace std;
11 const int MAXN=210000;
12 int n,now,down,up,ans,top;
13 int mx[MAXN],mi[MAXN];
14 struct ed
15 {
16    int v,id;
17 }a[MAXN];
18 bool comp(ed x,ed y)
19 {
20    if(x.v!=y.v)
21       return x.v<y.v;
22    return x.id<y.id;
23 }
24 int main()
25 {
26    scanf("%d",&n);
27    for(int i=1;i<=n;i++)
28       {
29          scanf("%d",&a[i].v);
30          a[i].id=i;
31       }
32    sort(a+1,a+n+1,comp);
33    top++; mi[top]=mx[top]=a[1].id;
34    for(int i=2;i<=n;i++)
35       {
36          if(a[i].v!=a[i-1].v)
37             top++ , mi[top]=a[i].id;
38          if(a[i].v!=a[i+1].v)
39             mx[top]=a[i].id;
40       }
41    now=mi[1]; down=1; up=0;
42    for(int i=2;i<=top;i++)
43       {
44          if(up)//一個斷點
45             {
46                if(mi[i]<now)
47                   { ans++; up=0; down=1; now=mi[i]; }
48                else
49                   now=mx[i];
50             }
51          else if(down)
52             {
53                if(mx[i]<now)
54                   now=mi[i];
55                else
56                   up=1,now=mx[i];
57             }
58       }
59    printf("%d\n",ans+1);
60    return 0;
61 }

BZOJ 2457 [BeiJing2011] 雙端隊列