令a[i]表示輸入第i個元素,d[i]表示從a[1]到a[i]中以a[i]結尾的最長子序列長度。對於任意的0 < j <= i-1,如果a(j) < a(i),則a(i)可以接在a(j)後面形成乙個以a(i)結尾的新的最長上公升子串行。對於所有的 0 < j <= i-1,我們需要找出其中的最大值。
dp狀態轉移方程:d[i] = max(j = 1, 2, 3, ..., i-1 且 a[j] < a[i])①
對於最長不下降子串行,怎樣實現o(nlogn)演算法呢?我們知道o(n^2)的演算法複雜度高的原因就在於要更新d[i]的值,就必須在1~i-1中列舉找到最大的d[j]的值才能最終確定d[i]的值,於是我們可以這樣思考,能否直接把1~i-1中最大的d[i]的值儲存起來,從而實現直接檢索呢?於是就有了如下類似貪心的演算法(個人理解)。
/*預處理*/
const int maxn = 40010;
const int inf = 0x3f3f3f3f;
int n;
int a[maxn], s[maxn];
int d[maxn];
void init()
其中d[i]和①是一樣的意義,而s陣列表示的意義是:所有最長上公升子串行長度為d[i]時的a[i]的最小值②,請仔細理解這一段話,即s[d[i]] = min。
舉例說明:
可以看出,s序列是嚴格的遞增序列,可以這樣理解:d[i'] = 2的最小值一定比d[i'']值為1的最小值大,因為d[i''] > d[i'],就這麼簡單。那麼知道了s的值有什麼用呢?或許聰明的讀者已經看出來了,對於最長不下降子串行,只要每次將乙個a[i]的值在s陣列中進行檢索,返回的小於等於a[i]最後乙個元素的下標的位置(或者「下乙個下標的位置」③)一定就是d[i]的長度。
為什麼呢?因為在這下標前面的元素一定是小於a[i]的,所以d[i]的值也就是返回的下標的值,不懂的可以用筆模擬一下,這也是前面我們為什麼要這樣定義②的目的所在。
這裡還有乙個地方要注意,就是最長上公升子串行的問題和最長不下降子串行的問題,如問題:1、2、3、5、5的結果是4還是5?待會我會給出滿意的解法。
另外正確的二分求上界的寫法,我也會給出,寫到這裡,筆者不得不感嘆:乙個正確的二分查詢也是很難寫的。。④
/*最長不下降子串行 poj 1631*/
int bsearch(int x, int y, int v) //二分求上界
return x;}
void dp()
printf("%d\n", ans);
}
如何求嚴格的最長上公升子串行呢?其實我們只要在二分時,把a[m] <= v改為a[m] < v即可。
對於最長不上公升子串行:模仿上面的定義,我們把s陣列的定義改為所有最長上公升子串行長度為d[i]時的a[i]的最大值,為什麼要是最大值呢?因為s陣列在這裡應該遵循嚴格的遞減序列才對,為了能夠檢索a[i],我們必須使得返回的下標一定就是d[i]的值,具體的實現方法:s的初始值賦為-inf,二分查詢的過程需要改一下,s陣列更新時使用max。
/*最長不上公升子串行 poj 1887*/
void init()
int bsearch(int x, int y, int v)
return x;}
void dp()
printf(" maximum possible interceptions: %d\n", ans);
}
這裡的二分是檢索a[i]在s陣列中的下標,如果沒有任何數比a[i]小,那麼返回值應該是s當前陣列的長度+1,不下降子串行剛好相反。
最長不下降子串行的優化:
對於最長不下降子串行,對於③我們發現,bsearch的過程相當於,對於乙個整數b來說,是求小於等於b的最後乙個元素的「下乙個下標」r是什麼?所以我們可以用到stl中的函式,upper_bound,這樣我們不必再去手寫二分,也就減少了一些**量。
/*核心***/
void dp()
printf("%d\n", ans);
}
最終,筆者還是不得不感嘆:乙個正確的二分查詢也是很難寫的。。。
對於④的解決方案:
最長上公升子串行 O nlogn
題目描述 input 輸入乙個整數n 表示接下來有 n 個數輸入。output 輸出當前數列最長上公升子串行的長度。直接上 最長下降子串行 最長山峰序列都可以以該問題為母問題 進行延伸。include include using namespace std define max 1000 int s...
最長上公升子串行O nlogn
假設已經計算出的兩個狀態a和b滿足a a a b 且d a d b 則對於後續所有的狀態i 即i a且i b 來說,a並不會比b差 如果b滿足a b a i 的條件,a肯定也滿足,且二者的d值相同 但反過來卻不一定了,a滿足a a a i 的條件時,b卻不一定滿足。換句話說,如果我們只保留a,一定不...
最長上公升子串行O nlogn
最近在做單調佇列,發現了最長上公升子串行o nlogn 的求法也有利用單調佇列的思想。最長遞增子串行問題 在一列數中尋找一些數,這些數滿足 任意兩個數a i 和a j 若i 設dp i 表示以i為結尾的最長遞增子串行的長度,則狀態轉移方程為 dp i max,1 j 這樣簡單的複雜度為o n 2 其...