题目描述:
题目背景: 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
样例说明:
1 2 | 2 1
−−−−
3 | 1 1 1
−−−−
2 0 1 | 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<cstring>
#include<string>
#include<cstdlib>
#include<cstdio>
#include<ctime>
#include<cmath>
#include<cctype>
#include<iomanip>
#include<algorithm>
using namespace std;
int a,b,r,c,p[510][510],tot,sum[510],maxp,minp=4100,ll,rr,mid;
int readint()
{
char ch;int i=0,f=1;
for(ch=getchar();(ch<'0'||ch>'9')&&ch!='-';ch=getchar());
if(ch=='-') {ch=getchar();f=-1;}
for(;ch>='0'&&ch<='9';ch=getchar()) i=(i<<3)+(i<<1)+ch-'0';
return i*f;
}
bool check(int x)
{
if(a*b*x>tot) return false;
int num1=0,num2=0,minsum=b*x,po=0,he=0,sum1=0;
for(int i=1;i<=r;i++)
{
he+=sum[i];
if(he<minsum)//加行
{
if(po==0) po=i;
continue;
}
else
{
if(po==0) po=i;
for(int k=1;k<=c;k++)
{
for(int j=po;j<=i;j++) sum1+=p[j][k];
if(sum1>=x) {num1++;sum1=0;}
}
if(num1>=b) {num2++;po=0;he=0;}
sum1=0;num1=0;
}
if(num2==a) return true;
}
return false;
}
int main()
{
//freopen("cut.in","r",stdin);
//freopen("cut.out","w",stdout);
r=readint();c=readint();a=readint();b=readint();
for(int i=1;i<=r;i++)
{
for(int j=1;j<=c;j++)
{
p[i][j]=readint();
sum[i]+=p[i][j];
if(p[i][j]<minp) minp=p[i][j];
}
tot+=sum[i];
}
ll=minp;rr=tot/(a*b);
while(ll<=rr)
{
mid=(ll+rr)>>1;
if(check(mid)==true)
ll=mid+1;
else rr=mid-1;
}
printf("%d",rr);
return 0;
}