-
Notifications
You must be signed in to change notification settings - Fork 109
/
Copy pathDivide and Conquer DP.cpp
57 lines (50 loc) · 1.59 KB
/
Divide and Conquer DP.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
// http://codeforces.com/blog/entry/8219
// Divide and conquer optimization:
// Original Recurrence
// dp[i][j] = min(dp[i-1][k] + C[k][j]) for k < j
// Sufficient condition:
// A[i][j] <= A[i][j+1]
// where A[i][j] = smallest k that gives optimal answer
// How to use:
// // compute i-th row of dp from L to R. optL <= A[i][L] <= A[i][R] <= optR
// compute(i, L, R, optL, optR)
// 1. special case L == R
// 2. let M = (L + R) / 2. Calculate dp[i][M] and opt[i][M] using O(optR - optL + 1)
// 3. compute(i, L, M-1, optL, opt[i][M])
// 4. compute(i, M+1, R, opt[i][M], optR)
// Example: http://codeforces.com/contest/321/problem/E
#include "../template.h"
const int MN = 4011;
const int inf = 1000111000;
int n, k;
ll cost[MN][MN], dp[811][MN];
inline ll getCost(int i, int j) {
return cost[j][j] - cost[j][i-1] - cost[i-1][j] + cost[i-1][i-1];
}
void compute(int i, int L, int R, int optL, int optR) {
if (L > R) return ;
int mid = (L + R) >> 1, savek = optL;
dp[i][mid] = inf;
FOR(k,optL,min(mid-1, optR)+1) {
ll cur = dp[i-1][k] + getCost(k+1, mid);
if (cur < dp[i][mid]) {
dp[i][mid] = cur;
savek = k;
}
}
compute(i, L, mid-1, optL, savek);
compute(i, mid+1, R, savek, optR);
}
void solve() {
cin >> n >> k;
FOR(i,1,n+1) FOR(j,1,n+1) {
cin >> cost[i][j];
cost[i][j] = cost[i-1][j] + cost[i][j-1] - cost[i-1][j-1] + cost[i][j];
}
dp[0][0] = 0;
FOR(i,1,n+1) dp[1][i] = inf;
FOR(i,2,k+1) {
compute(i, 1, n, 1, n);
}
cout << dp[k][n] / 2 << endl;
}