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 #includeview code3 #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 }
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 #includeview code3 #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 }
一類利用佇列優化的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次方...