题目背景
SOURCE:NOIP2015-SHY-7
题目描述
今天是ABC的生日,他制作了一个巧克力蛋糕!你可以把它理解成一个有 R×C 个小格子组成的矩形。每个格子上都有一些巧克力 chips ,第 i 行,第 j 列的格子上有 A[i][j] 个巧克力 chips 。
有 A×B 个人要出席 ABC 的生日晚会(包括ABC自己),每个人都想得到一块蛋糕。于是他想要把他的蛋糕切成 A×B 个小块。首先,他先横着切(A-1)刀,蛋糕就变成了 A 条,然后,对于每一条,他都纵着切(B-1)刀,就的到了(A×B)个小块。为了体现自己的大度, ABC 决定最后选蛋糕,而 ABC 的朋友就不会这么想了,他们总是拿走巧克力最多的蛋糕,所以,ABC 得到的蛋糕永远是巧克力最少的那一块。
聪明的 ABC 很喜欢吃巧克力,他想得到更多的巧克力,但是他正忙着准备自己的生日晚会,于是他来寻求你的帮助,希望你不要让他失望。
输入格式
第一行一个四个整数 R,C,A,B 。
接下来 R 行,每行 C 个数,描述每个格子上的巧克力数。
输出格式
输出一个整数,表示 ABC 最多能得到的巧克力数。
样例数据
输入
5 4 4 2
1 2 2 1
3 1 1 1
2 0 1 3
1 1 1 1
1 1 1 1
输出
3
备注
【样例说明】
12|21
−−−
3|111
−−−
201|3
−−−
1 1 | 1 1
1 1 | 1 1
【数据范围】
对 30% 的输入数据: 1≤R,C≤100,1≤A≤R,1≤B≤C;
对 100% 的输入数据:1≤R,C≤500,1≤A≤R,1≤B≤C,A[i][j]≤4000
分析:二分,check直接模拟就好(详见代码)。
代码
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<ctime>
#include<cmath>
#include<algorithm>
#include<cctype>
#include<iomanip>
#include<queue>
#include<set>
using namespace std;
int getint()
{
int sum=0,f=1;
char ch;
for(ch=getchar();!isdigit(ch)&&ch!='-';ch=getchar());
if(ch=='-')
{
f=-1;
ch=getchar();
}
for(;isdigit(ch);ch=getchar())
sum=(sum<<3)+(sum<<1)+ch-48;
return sum*f;
}
int R,c,a,b,tot,ans;
int cake[510][510],lin[510];
bool check(int x)
{
int minline=x*b,num1=0,num2=0,cnt1=0,cnt2=0,bj=0;//每一条至少需要x*b那么多chip,不然都不够分成b个x
for(int i=1;i<=R;++i)
{
num1+=lin[i];//加一行
if(num1>=minline)//判断从这一行切开在总数上是否满足大于x*b
{//如果能再看这一整条能否切成b块
for(int j=1;j<=c;++j)
{
for(int k=bj+1;k<=i;++k)
num2+=cake[k][j];
if(num2>=x)//只要这块蛋糕大于x就可以切断
{
cnt2++;
num2=0;
}
}
if(cnt2<b)//不到b块就要继续加行
{
cnt2=0;
num2=0;
}
else//到b块就可以切断
{
cnt1++;
num1=0;
num2=0;
cnt2=0;
bj=i;
}
}
}
return cnt1>=a;//判断能否切出a条
}
int main()
{
freopen("cut.in","r",stdin);
freopen("cut.out","w",stdout);
R=getint();c=getint();a=getint();b=getint();
for(int i=1;i<=R;++i)
for(int j=1;j<=c;++j)
{
cake[i][j]=getint();
tot+=cake[i][j];
lin[i]+=cake[i][j];//记一下一行有多少
}
int l=0,r=tot/(a*b)+1,mid;
while(l<=r)
{
mid=l+r>>1;
if(check(mid))
{
ans=mid;
l=mid+1;
}
else
r=mid-1;
}
cout<<ans<<'\n';
return 0;
}
本题结。