usingnamespace std; constint N = 20; int n, k; int a[N][N], s[N][N];
intcalc(int x1, int y1, int x2, int y2){ return s[x2][y2] - s[x2][y1 - 1] - s[x1 - 1][y2] + s[x1 - 1][y1 - 1]; }
boolcheck(int val){
for (int i = 0; i < 1 << (n - 1); i++) { // 存放横向的切法 vector<int> pos; // 这个地方很细节 pos.push_back(0); for (int j = 0; j < n - 1; j++) { if (i >> j & 1) { pos.push_back(j + 1); } }
if (pos.size() > k + 1) continue; int cnt = pos.size() - 1; pos.push_back(n); bool flag = true;
for (int j = 1; j <= n && flag; j++) { for (int p = 0; p < pos.size() - 1; p++) { int w = calc(pos[p] + 1, j, pos[p + 1], j); if (w > val) { flag = false; break; } } } if (!flag) continue;
int last = 1; // 枚举钟祥切法 for (int j = 1; j <= n; j++) { for (int p = 0; p < pos.size() - 1; p++) { int w = calc(pos[p] + 1, last, pos[p + 1], j); if (w > val) { // 如果大于val就在j - 1 的位置切一刀 // 下一个查询区间为[j, ?] last = j; cnt ++; break; } } } if (cnt <= k) returntrue; }
returnfalse; }
intmain( ) { ios::sync_with_stdio(false),cin.tie(0),cout.tie(0); int l = 0; cin >> n >> k; // 基本的二维前缀和 for (int i = 1; i <= n; i++) { for (int j = 1; j <= n; j++) { cin >> a[i][j]; l = max(a[i][j], l); s[i][j] = s[i - 1][j] + s[i][j - 1] - s[i - 1][j - 1] + a[i][j]; } }
// 二分寻找合适的大小 int r = 2e9; while (l < r) { int mid = l + r >> 1; if (check(mid)) r = mid; else l = mid + 1; }