天天看點

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