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
58
59
60
61
62
63
64
65
66
67
68
69
70
| // 더 많은 정보는 42jerrykim.github.io 에서 확인하세요.
#include <bits/stdc++.h>
using namespace std;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int N, K;
if (!(cin >> N >> K)) return 0;
const int SZ = N + 1;
// 2D prefix sum over the whole N x N matrix, flattened for cache locality
vector<long long> psum(1LL * SZ * SZ, 0);
auto I = [&](int r, int c) -> long long { return 1LL * r * SZ + c; };
for (int i = 1; i <= N; ++i) {
for (int j = 1; j <= N; ++j) {
int x; cin >> x;
psum[I(i, j)] = psum[I(i - 1, j)] + psum[I(i, j - 1)] - psum[I(i - 1, j - 1)] + x;
}
}
auto rect = [&](int r1, int c1, int r2, int c2) -> long long {
return psum[I(r2, c2)] - psum[I(r1 - 1, c2)] - psum[I(r2, c1 - 1)] + psum[I(r1 - 1, c1 - 1)];
};
auto cost = [&](int l, int r) -> long long {
// sum of u_ij for l <= i < j <= r; diagonal is zero; matrix symmetric
long long s = rect(l, l, r, r);
return s >> 1; // divide by 2
};
const long long INF = (1LL << 62);
vector<long long> dp_prev(SZ, INF), dp_cur(SZ, INF);
dp_prev[0] = 0;
for (int g = 1; g <= K; ++g) {
fill(dp_cur.begin(), dp_cur.end(), INF);
function<void(int,int,int,int)> solve = [&](int L, int R, int optL, int optR) {
if (L > R) return;
int mid = (L + R) >> 1;
long long bestVal = INF;
int bestK = -1;
int jStart = max(optL, g - 1);
int jEnd = min(optR, mid - 1);
for (int j = jStart; j <= jEnd; ++j) {
long long cand = dp_prev[j] + cost(j + 1, mid);
if (cand < bestVal) {
bestVal = cand;
bestK = j;
}
}
dp_cur[mid] = bestVal;
if (L == R) return;
solve(L, mid - 1, optL, bestK);
solve(mid + 1, R, bestK, optR);
};
solve(g, N, g - 1, N - 1);
dp_prev.swap(dp_cur);
}
cout << dp_prev[N] << '\n';
return 0;
}
|