bzoj
從左取和從右取沒有區別,本質上就是要分段。 設f
[i] f[i
]表示前
i i
個位置的最大值。
那麼相當於我們列舉乙個前面的位置
j' role="presentation">j
j,然後找到這一段中最大的s0
t2s 0t
2但是這樣子很不優秀。
我們貪心的思考一下,既然這一段最後加起來只能變成某乙個s0
s 0,
那麼,我們這一段開頭和結尾都一定要是s0
s 0,
否則我們把結尾那些不等於s0
s
0的單獨分開一段,
這樣子的答案一定不會更差,字首同理。
因此每次的s0
s
0一定由前面的某個s0
s
0轉移過來。
轉移是f[i
]=f[
j−1]
+s[i
]t2 f[i
]=f[
j−1]
+s[i
]t
2,其中t2
t
2是[j
,i] [j,
i]
中s[i]
s [i
]的個數。 發現t
2 t
2增長很快於y=
x y=x
,顯然這個式子是具有決策單調性的。
如果當前位置
k<
j k
<
j,那麼一旦
k k
的轉移優於了
j' role="presentation">j
j,那麼
k k
就永遠優於
j' role="presentation">j
j了。(這不顯然嗎?
那麼,對於每乙個
s s
都維護乙個單調棧(ve
ctor
' role="presentation">vec
torv
ecto
r) 每次將後面不優的全部彈出去,然後進行轉移。
注意幾點:
首先是不優的靠計算,記錄一下當前位置的字首
t t
的值,然後每次二分檢查單調棧裡面的第二個元素是否優於棧頂元素,也就是二分查詢一下超過的時間。
還有一種可能出現的情況,即當前第二個元素不比棧頂優秀,但是第三個元素比棧頂優秀。
對於棧頂的幾個元素,假設
a<
b<
c<
d' role="presentation">a
<
b<
c<
b<
c<
d,如果
a a
超過c' role="presentation">c
c的時間要早於
b b
超過d' role="presentation">d
d的時間。
那麼當b
b
超過d' role="presentation">d
d的時候,
a a
早就超過
d' role="presentation">d
d了,那麼
b b
是沒有意義的。
所以對於當前位置
i' role="presentation">i
i,我們檢查棧頂元素和第二個元素超過
i i
的時間
如果第二個元素超過
i' role="presentation">i
i的時間更早,那麼第乙個元素就沒有意義了,可以直接彈掉。
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using
namespace
std;
#define ll long long
#define rg register
#define max 111111
inline
int read()
ll f[max];
vector
g[max];
int n,a[max],num[max],s[max];
ll calc(int j,int x)
int time(int x,int y)
return ret;
}int main()
printf("%lld\n",f[n]);
}
bzoj4709 檸檬 單調棧,DP,斜率優化
目錄錯誤 s是值等於a i 的字首和 轉移方程 f i max f i f j 1 a i s i s j 1 s i s j 1 不難寫出暴力方程 by wxyww baoli memset f,0x3f,sizeof f f 0 0 for int i 1 i n i 關於此題的單調性 特性1每...
BZOJ1037動態規劃
資料範圍很小,可以用4維儲存下前i個男孩j個女孩,從這一位往前的所有點中男 女的差最大為x,女 男為y的方案數 主動遞推 f i 1 j x 1 max y 1 0 f i j x y f i j 1 max x 1 0 y 1 f i j x y 最後答案為 sigma x sigma y f n...
BZOJ1040 騎士(動態規劃)
bzoj 對於每一組厭惡的關係 顯然是連邊操作 如果是一棵樹的話 很顯然的樹型dp 但是,現在相當於有很多個基環 也就是在一棵樹的基礎上再加了一條邊 這個時候怎麼辦,暴力拆掉基環 拆掉任意一條邊 跑兩遍dp 計算出強制不選兩個點中某乙個的最大值 此時就是這個基環的最大值 不用拆掉所有的邊,因為只要拆...