Brownie Slicing 二分+二维前缀和
链接:http://10.20.2.244/oj/exercise/problem?problem_id=21407(自家oj)
题意:
给你一个蛋糕,R行C列 ,每个点有巧克力碎屑(如下)
1 2 2 1
3 1 1 1
2 0 1 3
1 1 1 1
1 1 1 1
你要先横着切a-1刀,将蛋糕分为a块,然后对于每一块,分别竖着切b-1刀
将整个蛋糕分成a*b块,求巧克力屑最少的一块最多有多少屑
思路:对于这种最大求最小,或者最小求最大的题目,我们往往会先往二分方面想
对于这道题,就是用二分的解法。
这道题让我们求最小值最大。
在计算的时候,我们先计算出二维前缀和。然后开始跑check
check部分,我们先计算只有一行的情况,如果不满足((区间值>=mid的个数)>=B)),就继续增加行数,直到满足为止
然后最后看看hang是否大于等于A,大于等于则满足情况,否则不满足;
代码如下:
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 }