天天看点

Brownie Slicing 二分+二维前缀和

题意:

给你一个蛋糕,R行C列 ,每个点有巧克力碎屑(如下)

1 2 2 1

3 1 1 1

2 0 1 3

1 1 1 1

你要先横着切a-1刀,将蛋糕分为a块,然后对于每一块,分别竖着切b-1刀

将整个蛋糕分成a*b块,求巧克力屑最少的一块最多有多少屑

思路:对于这种最大求最小,或者最小求最大的题目,我们往往会先往二分方面想

   对于这道题,就是用二分的解法。

   这道题让我们求最小值最大。

   在计算的时候,我们先计算出二维前缀和。然后开始跑check

   check部分,我们先计算只有一行的情况,如果不满足((区间值>=mid的个数)>=B)),就继续增加行数,直到满足为止

Brownie Slicing 二分+二维前缀和
Brownie Slicing 二分+二维前缀和

1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int inf=0x3f3f3f3f;
 4 const int maxn=5e2+10;
 5 int r,c,A,B;
 6 int sum[maxn][maxn];
 7 int a[maxn][maxn];
 8 int cal(int x1,int y1,int x2,int y2){
 9     int val=sum[x2][y2]-sum[x1-1][y2]-sum[x2][y1-1]+sum[x1-1][y1-1];
10     return val;
11 }
12 void init()
13 {
14     for(int i=1;i<=r;i++)
15         for(int j=1;j<=c;j++)
16             sum[i][j]=sum[i][j-1]+a[i][j];
17     for(int i=1;i<=r;i++)
18         for(int j=1;j<=c;j++)
19             sum[i][j]+=sum[i-1][j];
20 }
21 int check(int mid)
22 {
23     int nowL=1;int nowR=1;
24     int hang=0;
25     while(nowR<=r){
26         int tmp=1;int lie=0;
27         for(int i=1;i<=c;i++){
28             if(cal(nowL,tmp,nowR,i)>=mid){
29                 lie++;
30                 tmp=i+1;
31             }
32         }
33         if(lie<B) nowR++;
34         else{
35             hang++;
36             nowL=nowR+1;
37             nowR=nowL;
38         }
39     }
40     if(hang>=A) return 1;
41     else return 0;
42 }
43 int main()
44 {
45     scanf("%d%d%d%d",&r,&c,&A,&B);
46     for(int i=1;i<=r;i++){
47         for(int j=1;j<=c;j++){
48             scanf("%d",&a[i][j]);
49         }
50     }
51     init();
52     int L=0;int R=inf;
53     int ans;
54     while(L<=R){
55         int mid=L+R>>1;
56         if(check(mid)){
57             L=mid+1;
58             ans=mid;
59         }
60         else{
61             R=mid-1;
62         }
63     }
64     printf("%d\n",ans);
65     return 0;
66 }      

View Code