[找规律] 多校联合第二场 B题 Buildings


Buildings

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)
Total Submission(s): 0    Accepted Submission(s): 0


Problem Description
  
  
Your current task is to make a ground plan for a residential building located in HZXJHS. So you must determine a way to split the floor building with walls to make apartments in the shape of a rectangle. Each built wall must be paralled to the building's sides. The floor is represented in the ground plan as a large rectangle with dimensions n×m , where each apartment is a smaller rectangle with dimensions a×b located inside. For each apartment, its dimensions can be different from each other. The number a and b must be integers. Additionally, the apartments must completely cover the floor without one 1×1 square located on (x,y) . The apartments must not intersect, but they can touch. For this example, this is a sample of n=2,m=3,x=2,y=2 .
To prevent darkness indoors, the apartments must have windows. Therefore, each apartment must share its at least one side with the edge of the rectangle representing the floor so it is possible to place a window. Your boss XXY wants to minimize the maximum areas of all apartments, now it's your turn to tell him the answer.
 

Input
  
  
There are at most 10000 testcases. For each testcase, only four space-separated integers, n,m,x,y(1n,m108,n×m>1,1xn,1ym) .
 

Output
  
  
For each testcase, print only one interger, representing the answer.
 

Sample Input
  
  
2 3 2 2 3 3 1 1
 

Sample Output
  
  
1 2
Hint
Case 1 :
You can split the floor into five 1×1 apartments. The answer is 1. Case 2:
You can split the floor into three 2×1 apartments and two 1×1 apartments. The answer is 2.
If you want to split the floor into eight 1×1 apartments, it will be unacceptable because the apartment located on (2,2) can't have windows.


题意:给定一块 n*m 的空地,需要在这块空地上除(x,y)点以外的所有区域全都分割成相应的矩形,其中坐标为x,y的点不需要分割,要求满足所有分割出来的矩形都至少有一边接触到最外层。在满足条件的前提下,你要将矩形分割成尽量小的面积,求此时分割后最大矩形的面积。


最直接的想法就是,要想完整地把整块矩形分割出来并且满足条件,那么中间的部分是决定矩形面积的最重要的地方。由于矩形可以任意分割,所以分割成1*k的长条一定是使面积最小的选择。如果不存在被挖去的点(x,y),只要取到最中间的块并且使这个矩形尽量小,就可以满足题目所给的条件。很容易证明这个矩形的面积是min((n,m)+1) / 2 。

然而因为有了被挖掉的这个点的加入,出现了一种非常操蛋的情况:

 


假设这个区域在y轴上非常长,刚好x周把整个矩形的终点挡住了,那么用刚才的公式就不能求对应的矩形面积。因为x的存在,使x轴上的长条面积无法再取成原来的一半,必须从x断开的右边位置开始。此时从x的右边开始,一整条的长度就是当前矩形面积的最小值。


以此类推,当整块的面积不同,以及x出现的位置不同时,也有可能从x的断开的左边位置,上边位置或者下边位置出现相同的情况。此时如果要算出矩形的最小面积,就要算出x的四周往三个方向延伸到边缘的最小长度


对x的四个方向,求其对应位置的矩形的最小值,得到四个当前值,这四个当前值中,最大的那个值就是需要求出的矩形最大面积。

除此以外,还有一种特殊情况,当整个矩形的长宽相等且均为奇数,且被挖掉的点刚好是其中点时,其最短距离可以刚好减一,因为原本一定要计算在内的位置被删去了。在其他任何位置,中点造成的数值改变都没有太大的影响。


我们只要考虑m>n的情况,当m<n时,只要把m,n 和 x,y 翻转过来,就可以得到完全相同的情况。

再说一句,这代码写的真是漂亮,原本题解不想发的,实在忍不住要分享出来。。

#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;

int main()
{
    int m,n,x,y;
    while(~scanf("%d%d%d%d",&m,&n,&x,&y))
    {

        if (m<n) {swap(m,n);swap(x,y);}
        int Mmid = (m+1)/2;
        int Nmid = (n+1)/2;

        int up = n - Nmid + 1;
        int down = Nmid;
        int left = Mmid;
        int right = m - Mmid+1;
       // printf("中点距上下左右的距离:%d %d %d %d\n",up,down,left,right);
        int midMax = min(min(up,down),min(left,right));
        if(m == n && (m&1) && (n&1) && x==(m+1)/2 && y == (m+1)/2)
            midMax--;
      //  printf("%d\n",midMax);

        int Ux = x;
        int Uy = y+1;
        int Uup = n - Uy +1;
        int Uleft = Ux;
        int Uright =  m - Ux +1;
      //  printf("x点上方 上,左,右的距离:%d %d %d\n",Uup,Uleft,Uright);
        int Umax = min(min(Uup,Uleft),Uright);
      //  printf("%d\n",Umax);

        int Dx = x;
        int Dy = y-1;
        int Ddown = Dy;
        int Dleft = Dx;
        int Dright = m - Dx +1;
      //  printf("x点下方 下,左,右的距离:%d %d %d\n",Ddown,Dleft,Dright);
        int Dmax = min(min(Ddown,Dleft),Dright);
      //  printf("%d\n",Dmax);

        int Lx = x-1;
        int Ly = y;
        int Lup = n - Ly +1;
        int Ldown = Ly;
        int Lleft = Lx;
      //  printf("x点左边 上,下,左的距离:%d %d %d\n",Lup,Ldown,Lleft);
        int Lmax = min(min(Lup,Ldown),Lleft);
      //  printf("%d\n",Lmax);

        int Rx = x+1;
        int Ry = y;
        int Rup = n - Ry+1;
        int Rdown = Ry;
        int Rright = m - Rx +1;
      //  printf("x点右边 上,下、右的距离:%d %d %d\n",Rup,Rdown,Rright);
        int Rmax = min(min(Rup,Rdown),Rright);
     //   printf("%d\n",Rmax);

        int totalmax = max(max(max(Umax,Dmax),max(Lmax,Rmax)),midMax);
        printf("%d\n",totalmax);
    }
    return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值