[题目链接]
https://www.lydsy.com/JudgeOnline/problem.php?id=1169
[算法]
首先DFS枚举出横着切的
然后二分 + 贪心即可
时间复杂度 : O(2 ^ N * N ^ 2logN)
[代码]
#include<bits/stdc++.h> using namespace std; typedef long long ll; typedef long double ld; typedef unsigned long long ull; #define N 20 const int inf = 2e9; int n , m , r , s , cnt; ll ans; ll a[N][N] , sum[N][N] , dp[N][N] , b[N]; template <typename T> inline void chkmax(T &x,T y) { x = max(x,y); } template <typename T> inline void chkmin(T &x,T y) { x = min(x,y); } template <typename T> inline void read(T &x) { T f = 1; x = 0; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == '-') f = -f; for (; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + c - '0'; x *= f; } inline int calc(int x) { int ret = 0; for (int i = x; i; i -= i & (-i)) ++ret; return ret; } inline ll calc_sum(int X1 , int Y1 , int X2 , int Y2) { return sum[X2][Y2] - sum[X1 - 1][Y2] - sum[X2][Y1 - 1] + sum[X1 - 1][Y1 - 1]; } inline bool check(ll limit) { int pre = 1 , cut = 0; for (int i = 1; i <= m; ++i) { for (int j = 1; j <= cnt; ++j) { if (calc_sum(b[j - 1] + 1 , i , b[j] , i) > limit) return false; } } for (int i = 1; i <= m; ++i) { ll value = 0; for (int j = 1; j <= cnt; ++j) { if (calc_sum(b[j - 1] + 1 , pre , b[j] , i) <= limit) continue; else { pre = i; ++cut; } } } return cut <= s; } inline ll getans(ll S) { cnt = 0; for (int i = 0; i < n; ++i) if (S & (1 << i)) b[++cnt] = i + 1; b[++cnt] = n; ll l = 0 , r = ans , ret = inf; while (l <= r) { int mid = (l + r) >> 1; if (check(mid)) { ret = mid; r = mid - 1; } else l = mid + 1; } return ret; } int main() { read(n); read(m); read(r); read(s); for (int i = 1; i <= n; ++i) { for (int j = 1; j <= m; ++j) { read(a[i][j]); sum[i][j] = sum[i - 1][j] + sum[i][j - 1] - sum[i - 1][j - 1] + a[i][j]; } } ans = sum[n][m]; for (int i = 0; i < (1 << n); ++i) { if (calc(i) == r) chkmin(ans , getans(i)); } printf("%lld " , ans); return 0; }