Brownie Slicing G

题目链接:https://www.luogu.com.cn/problem/P3017

题意:

给定一个矩阵,需要切成axb块,使每块的最小值尽量大。

思路:

显然二分最大化最小值

关键在于如何统计块数,即如何写check函数

不妨先按一行一行来切,在每一行中,当切出的块大于等于mid的时候,转而切下一块

如果这一行能够切出来b块,那很好

否则一定要多加一行,重新再切

这样满足每一“大行”都有b块

那么我们只需要看“大行”的数量是否大于等于a即可

由于在矩阵上操作,需要使用二维前缀和加速求解

int g[550][550];
int r,c,a,b;
int pre[550][550];
int cal(int x1,int y1,int x2,int y2){
    return pre[x2][y2]-pre[x2][y1-1]-pre[x1-1][y2]+pre[x1-1][y1-1];
}
bool check(int mid){
    int cnta=0;
    int now=1;
    for(int i=1;i<=r;i++){
        int sum=0;
        int p=1;
        for(int j=1;j<=c;j++){
            if(cal(now,p,i,j)>=mid){
                sum++;
                p=j+1;
            }
        }

        if(sum>=b){
            cnta++;
            now=i+1;
        }
    }
    return cnta>=a;
}
void solve(){
    cin>>r>>c>>a>>b;
    for(int i=1;i<=r;i++){
        for(int j=1;j<=c;j++){
            cin>>g[i][j];
        }
    }
    for(int i=1;i<=r;i++){
        for(int j=1;j<=c;j++){
            pre[i][j]=-pre[i-1][j-1]+pre[i][j-1]+pre[i-1][j]+g[i][j];
        }
    }
    int l=0,r=1e15;
    int res=0;
    while(l<=r){
        int mid=l+r>>1;
        if(check(mid)){
            l=mid+1;
            res=mid;
        }else{
            r=mid-1;
        }
    }
    cout<<res<<endl;
}
posted @ 2025-04-20 11:53  Marinaco  阅读(20)  评论(0)    收藏  举报
//雪花飘落效果