[BALTIC 2008] Grid

[题目链接]

         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\n" , ans);
        
        return 0;
    
}

 

posted @ 2019-04-27 11:17  evenbao  阅读(156)  评论(0编辑  收藏  举报