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;
}

浙公网安备 33010602011771号