1. 程式人生 > 實用技巧 >O(nlogn)求出最長不上升子序列的長度

O(nlogn)求出最長不上升子序列的長度

1.實現方式

首先我們需要一個數組a,儲存從第1個到第n個導彈的高度

然後一個數組d(其實是個棧),儲存不上升序列

把a中的每個元素挨個加到d裡面:

(a中第i個元素為a[i],d長度為len,d中最後一個(也是最小的一個)為d[len])

如果a[i] <= d[len],說明a[i]可以接在d後面(而整個d還是有序的),那就簡單粗暴地把a[i]丟進d:

d[++len] = a[i]

如果a[i] > d[len],說明a[i]接不上

但是我們發揚瞎搞精神:接的上要接,接不上創造條件也要接!

強行把a[i]塞進去:

在d中找到第一個小於a[i]的數,把它踹了,用a[i]代替它!(為什麼正確在下面)

假設這個數是y,怎樣踹掉它呢?

很明顯,我們需要使用lower_bound和upper_bound來查詢

第一步,找一個聽起來無比正確的理由,比如它佔著位置不幹活啦,幹起活來還不如a[i]啦,naive啦,它too young啦,too simple啦......反正能騙過lower_bound和upper_bound就行

(lower_bound&&upper_bound:你當我們傻)(w1049:真聰明)

接下來,特別有正義感的lower_bound和upper_bound就會去把y給拎出來

第二步,考慮使用什麼

我們知道,要求的是最大不上升子序列長度,也就是如果兩個元素相等也是可以的

所以我們踹人就不用踹等於a[i]的了

結合上面,應該使用upper_bound(終於想起來它了)並且使用>作為比較器(這是個下降序列)

第三步,直接開搞

int p = upper_bound(d + 1, d + 1 + len, a[i], greater<int>()) - d;
  
d[p] = a[i];

成功把a[i]塞了進去

2.為什麼正確

顯然成立

如果y在末尾,由於y < a[i],所以y後面能接的不如a[i]多,y讓位給a[i]可以讓序列更長

如果y不在末尾,那y有生之年都不會再被用到了,直接踹了y就行,y咋樣,who care?

注意到lower_bound只能在有序序列中使用,此時d還有序嗎?

當然有序。(本文第一個句號)

假設y前一個y1,y後一個是y2,則

y1 > y > y2y1>y>y2

因為y是第一個小於a[i]的,所以

y1 > a[i]y1>a[i]

又因為

a[i] > y > y2a[i]>y>y2

所以

y1 >y1>a[i]> y2>y2

對比下原來的式子

y1 >y1>y> y2>y2

a[i]可以完美代替y,至於y以後咋辦,who care?

對於最長上升子序列,只需要把上面的過程通通換一下符號

可以用以下方法證明:

反之亦然同理,推論自然成立,略去過程QED,由上可知證畢(多麼美妙的證明)

實際上,d[i]d[i]的含義是:最大不上升子序列長度為ii時,最優的結尾元素。

3.程式碼:

for(int i=2;i<=n;i++)
	if(d[len]>=a[i])d[++len]=a[i];
	else {
		int p=upper_bound(d+1,d+1+len,a[i],greater<int>())-d;
		d[p]=a[i];
	}

最後len就是要求的最大不上升子序列長度

但要注意的是,d中儲存的並不是最大不上升子序列!

原因如下:

即得易見平凡,仿照上例顯然,留作習題答案略,讀者自證不難

4.對樣例模擬:

在這裡推薦一下DevC++的偵錯程式(不用DevC++的當我沒說)

(還是不要推薦了)

1.我們把a[i]**(389)**加入d:

2.i=2,此時a[i](207)<=d[len](389),把a[2]加入d:

3.i=3,此時a[i](155)<=d[len](207),把a[3]加入d:

4.i=4,此時a[i](300)>d[len](155),不能直接加入,所以準備踹人

5.找出d中第一個小於a[i](300)的(即207),用a[i]換掉

6.i=5,此時a[i](299)>d[len](155),不能直接加入,所以準備踹人

7.找出d中第一個小於a[i](299)的(即155),用a[i]換掉

8.i=6,此時a[i](170)<=d[len](299),把a[6]加入d:

9.i=7,此時a[i](158)<=d[len](170),把a[7]加入d:

10.i=8,此時a[i](65)<=d[len](158),把a[8]加入d:

至此,得到最大不上升子序列長度len=6

by——w1049344862

洛谷

——END——