1. 程式人生 > 實用技巧 >Brownie Slicing 二分+二維字首和

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 }
View Code