Description
Bessie烘焙了一块巧克力蛋糕。这块蛋糕是由
R∗C(1<=R,C<=500)
个小的巧克力蛋糕组成的。 第
i
行,第
1 2 2 1
3 1 1 1
2 0 1 3
1 1 1 1
1 1 1 1
Bessie必须把蛋糕切成4条,每条分成2块。Bessie能像这样切蛋糕:
1 2 | 2 1
---------
3 | 1 1 1
---------
2 0 1 | 3
---------
1 1 | 1 1
1 1 | 1 1
因此,其他贪得无厌的牛拿完后,Bessie仍能够拿走3个巧克力碎屑。
Input
第1行: 四个空格隔开的数:
R
,
第2-
R+1
行: 第
i+1
行有
C
个整数,
Output
第1行:一个整数:Bessie保证能拿到的最多碎屑数。
Sample Input
5 4 4 2
1 2 2 1
3 1 1 1
2 0 1 3
1 1 1 1
1 1 1 1
Sample Output
3
HINT
Source
Gold
方法
二分答案,check函数里有两个优化:第一个就是枚举横坐标时,如果从当前点切一刀还不够(蛋糕价值下限*要纵向切的块数)时,就说明无论怎么切也满足不了条件,那么就不要枚举纵向的切法了;第二个就是如果搜索纵切方案时,前面的切法已经可以满足限制时,就可以跳出不用再枚举了。
代码
#include <cstdio>
const int maxn=500;
int r,c,a,b;
int map[maxn+10][maxn+10];
int sum[maxn+10][maxn+10];
//sum数组是这个矩阵的前缀和
int left,right,ans;
int check(int lim)
{
int prex=1,cntx=0;
for(int i=1; i<=r; i++)
{
int prey=1,cnty=0;
if(sum[i][c]-sum[prex-1][c]<lim*b)
//优化1,应该能优化50%
{
continue;
}
for(int j=1; j<=c; j++)
{
if(sum[i][j]-sum[prex-1][j]-sum[i][prey-1]+sum[prex-1][prey-1]>=lim)
{
cnty++;
prey=j+1;
}
if(cnty>=b)
//优化2
{
break;
}
}
if(cnty>=b)
{
cntx++;
prex=i+1;
}
}
if(cntx>=a)
{
return 1;
}
else
{
return 0;
}
}
int main()
{
scanf("%d%d%d%d",&r,&c,&a,&b);
for(int i=1; i<=r; i++)
{
for(int j=1; j<=c; j++)
{
scanf("%d",&map[i][j]);
sum[i][j]=map[i][j]+sum[i][j-1]+sum[i-1][j]-sum[i-1][j-1];
}
}
right=sum[r][c]/(a*b);
//这是答案的上限
while(left<=right)
//二分枚举答案
{
int mid=(left+right)>>1;
if(check(mid))
{
ans=mid;
left=mid+1;
}
else
{
right=mid-1;
}
}
printf("%d\n",ans);
return 0;
}