[NOIP模拟][二分]cut

题目描述:
题目背景: 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;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值