2.2 單調棧
將數列
\left\ \right\}
命題1:數列
\left\ \right\}
非遞增子串行的最小劃分數等於其最長遞增子串行的長度。
證明:
設數列
\left\ \right\}
非遞增子串行的最小劃分數為k,數列
\left\ \right\}
最長遞增子串行的長度為p。
顯然最長遞增子串行中不可能有兩個數在同乙個劃分裡面,所以有k⩾p
k \geqslant p
k⩾p。
其次,可以在每個劃分裡面拿出乙個數出來,構成乙個遞增子串行(這裡暫時不解釋),這樣k⩽p
k \leqslant p
k⩽p。
綜上可推出k=p
k=pk=
p。命題2:數列
\left\ \right\}
遞增子串行的最小劃分數等於其最長非遞增子串行的長度。
命題3:數列
\left\ \right\}
非遞減子串行的最小劃分數等於其最長遞減子串行的長度。
命題4:數列
\left\ \right\}
遞減子串行的最小劃分數等於其最長非遞減子串行的長度。
d pi
dp_dp
i表示以第i
ii個數結尾的最長遞增子串行的長度。
d pi
=maxj
⩽i−1
∧a
j (aj) +1 dp_= \max_ < a_}(a_)+1 dpi =maxj⩽ i−1∧ aj(a j)+ 1。最終要求的最長遞增子串行為max 1⩽i⩽ n(dp i) max_(dp_) max1⩽i ⩽n( dpi )對於每個dpi dp_dp i都需要在[1, i−1] [1,i-1] [1,i−1 ]中尋找最優解,所以時間複雜度為o(n 2) \mathcal(n^) o(n2)。#include
#include
using
namespace std;
const
int n=
1e3+10;
int a[n]
,dp[n]
,n;int
main()
} res=
max(res,dp[i]);
}printf
("%d\n"
,res);}
return0;
}最長遞增子串行也可以通過"單調棧"實現(事實上這不是真正意義上的單調棧,因為在操作過程中修改了棧中間的元素,破壞了fifo的性質)。這裡簡單介紹一下演算法,暫不作解釋:
對於每個需要入棧的元素,比較其與棧頂元素的大小
如果棧為空或比棧頂元素大,則直接入棧
否則,用其替換棧內第乙個大於或等於他的元素
最壞的情況下,每次的入棧元素都需要替換,替換過程中使用二分查詢,時間複雜度為olo
g(n)
\mathcal
olog(n
)。總的時間複雜度為o(n
log(
n)
)\mathcal(nlog(n))
o(nlog
(n))
#include
#include
#include
using
namespace std;
int n;
intmain()
printf
("%d\n"
,stk.
size()
);}return0;
}
hdu1257 最少攔截系統
解釋 當炮彈乙個接乙個的從空中飛來時,系統可以攔住比它攔住前乙個高度低的炮,比前乙個高的不攔,給第二個系統攔 problem description 某國為了防禦敵國的飛彈襲擊,發展出一種飛彈攔截系統.但是這種飛彈攔截系統有乙個缺陷 雖然它的第一發炮彈能夠到達任意的高度,但是以後每一發炮彈都不能超過...
hdu 1257 最少攔截系統
題目大意 給定一串飛彈的高度,問最少需要多少飛彈攔截系統。思路 lis 分析 首先,至少需要一套攔截系統,一開始可以打到第一顆飛彈的位置。之後每來一顆飛彈更新一下系統能打到的高度。一旦有一顆飛彈所有系統都打不到了,增加乙個系統。那麼就會得到乙個序列,每個系統目前能打到的最高位置。這個序列是遞增的,後...
HDU1257 最少攔截系統
problem description 某國為了防禦敵國的飛彈襲擊,發展出一種飛彈攔截系統.但是這種飛彈攔截系統有乙個缺陷 雖然它的第一發炮彈能夠到達任意的高度,但是以後每一發炮彈都不能超過前一發的高度.某天,雷達捕捉到敵國的飛彈來襲.由於該系統還在試用階段,所以只有一套系統,因此有可能不能攔截所有...