一類斜率優化的dp(特有性質 只能連續,不能交叉)

2022-08-24 20:54:08 字數 3670 閱讀 1222

hdu3480

給定乙個有n個數的集合,將這個集合分成m個子集,要求子集的並等於全集

求花費最小。

花費為該子集的(最大數-最小數)的平方。

我們將n個數排序,

a < b < c < d

那麼不可能a,c乙個集合,b,c乙個集合

明顯a,b乙個集合,c,d乙個集合更優

也就是說某乙個數只能和它前面的連續幾個數合起來形成乙個子集。 正是因為有這個性質才能dp

dp[i][j]表示第j個數在第i個集合的最小花費

dp[i][j] = min(dp[i][j],dp[i-1][k]) 1<=kdp[i-1][k1] + (a[j]-a[k1+1])^2 < dp[i-1][k2]+(a[j]-a[k2+1])^2

dp[i-1][k1]+a[k1]^2-(dp[i-1][k2]+a[k2]^2) < 2a[j]*(a[k1+1]-a[k2+1])

這樣就能夠用斜率優化了,由於是求最小值,所以維護乙個下凸包就行了。

1 #include 2 #include 

3 #include 4 #include 5 #include 6 #include 7 #include 8 #include 9 #include 10 #include

11 #include

12 #include 13

using

namespace

std;

14#pragma warning(disable:4996)

15#pragma comment(linker, "/stack:1024000000,1024000000")

16 typedef int

ll;

17const

int inf = 1

<<30;18

/*19

給定乙個有n個數的集合,將這個集合分成m個子集,要求子集的並等於全集

20求花費最小, 花費為什麼每個集合的(最大值-最小值)的平方

2122

dp[i][j]表示第j個數在第i個集合的最小花費

23用滾動陣列壓縮空間

24*/

2526

const

int n = 10000 + 10;27

const

int m = 5000 + 10;28

ll a[n];

29 ll dp[2

][n];

30int

q[n], head, tail;

31ll dw(ll a, ll b)

3235 ll getup(int k1, int k2, int

c)36

39 ll getdown(int k1, int

k2)40

43int

main()

4472 c ^= 1;73

}74 printf("

case %d: %d\n

",k, dp[c][n]);75}

76return0;

77 }

view code

hdu3405

n頭牛,分成幾組,每組至少有k頭牛

要求費用最小,

費用是每組所有牛的moo,減去該組中最小的moo

將moo排序

那麼如果是分成兩組的話,那麼不可能是a,c一組, b,d一組

a,b,一組比c,d一組肯定更優。

又遇到了有這種性質的題目, 連續比交叉更優,這樣,才能用dp來解決,

dp[j]表示以j結尾的team的最小花費

(dp[k1]-sum[k1]+k1*moo[k1+1]) - (dp[k2]-sum[k2]+k2*moo[k2+1]) < i*(moo[k1+1]-moo[k2+1])

dp[k1]+k1*moo[k1+1] - (dp[k2]+k2*moo[k2+1]) < i * (moo[k1+1]-moo[k2+1])

所以維護遞增的斜率

1 #include 2 #include 

3 #include 4 #include 5 #include 6 #include 7 #include 8 #include 9 #include 10 #include

11 #include

12 #include 13

using

namespace

std;

14#pragma warning(disable:4996)

15#pragma comment(linker, "/stack:1024000000,1024000000")

16typedef __int64 ll;

17const

int inf = 1

<<30;18

/*19

n頭牛,分成幾組,每組至少有k頭牛

20要求費用最小,

21費用是每組所有牛的moo,減去該組中最小的moo

22a < b < c < d

23那麼如果是分成兩組的話,那麼不可能是a,c一組, b,d一組

24a,b,一組比c,d一組肯定更優。

25又遇到了有這種性質的題目, 連續比交叉更優,這樣,才能用dp來解決,

26dp[j]表示以j結尾的team的最小花費

27(dp[k1]-sum[k1]+k1*moo[k1+1]) - (dp[k2]-sum[k2]+k2*moo[k2+1]) < i*(moo[k1+1]-moo[k2+1])

28dp[k1]+k1*moo[k1+1] - (dp[k2]+k2*moo[k2+1]) < i * (moo[k1+1]-moo[k2+1])

29所以維護遞增的斜率

3031

*/32

const

int n = 400000 + 10;33

ll moo[n], dp[n], sum[n];

34int

q[n], head, tail;

3536 ll getup(int k1, int

k2)37

40 ll getdown(int k1, int

k2)41

44int

main()

4553 sort(moo + 1, moo + n + 1

);54

for (int i = 1; i <= n; ++i)

55 sum[i] = moo[i] + sum[i - 1

];56

for (int i = t; i <= n; ++i)

57 dp[i] = sum[i] - i*moo[1

];58

59 head = tail = 0

;60 q[tail++] = 0

;61 q[tail++] =t;

62int k = t + 1;63

for (int i = 2*t; i <= n; ++i)

6472 printf("

%i64d\n

", dp[n]);73}

74return0;

75 }

view code

一類利用佇列優化的DP

這是乙個 o n 2 的狀態和轉移方程 f i,j left f i 1,j 1 k 1 leq j max j 1 end right.這個方程目測是 theta n 2 的,但是實際上,上面的那個方程只是把陣列整體位移了,下面的方程只是在位移後的陣列開端添上了乙個數,這個完全可以通過佇列來實現,...

一類巧妙利用利用失配樹的序列DP

求長度為 text 的包含給定連續子串 text 的 0 1 串的個數。t 15 通常來說這種題目應該立刻聯想到狀壓 dp 與取反集 這樣就不用考慮大量重複情況的容斥問題。設 f 表示前 i 個字元 最後 t 個字元為 s 不包含給定連續子串的情況數,狀態轉移方程簡單不述。時間複雜度 theta 2...

LGP4859, 一類奇怪的容斥套DP

漫山遍野都是fake的光影。lgp4859 已經沒有什麼好害怕的了 給定兩個長度為n的陣列a和b,將a中元素與b中元素配對,求滿足ai bj的配對 i,j 個數減去滿足ai 某年noi歡樂賽 決鬥 給定兩個長度為n的陣列a和b,將a中元素與b中元素隨機配對,求滿足ai bj的配對 i,j 個數k次方...