[NOIP2017模拟]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

备注
【样例说明】
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;
}

本题结。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值