Codeforces round 1031 div2 B题题解

题目来源及意义

题目链接
codesforces 上面的题非常考验编程水平 逻辑思维 ,高强度的比赛时可以磨练我们的抗压能力。为未来在被HR连问时,可以做到从容不迫,答出比标准答案更为逆天的答案与思路。最后祝愿大家都可以拿到ACM的金牌,保送世界名校。走出China,走出亚洲,为自己,为家乡,为祖国而战!

题意

屋顶是平面上一个尺寸为 w×h 的矩形,其左下角位于点 (0,0)。你的团队需要用相同的 a×b 尺寸的屋面板完全覆盖该屋顶,且需满足以下条件:
屋面板不可旋转(甚至不能旋转 90 度);
屋面板不可重叠(但边缘可接触);
屋面板可延伸至屋顶边界之外。
团队中的一位新手已在屋顶上放置了两块屋面板,这两块板不重叠且各自部分覆盖屋顶。你的任务是判断能否在不移除这两块板的前提下,完全铺盖整个屋顶。
输入格式
第一行包含测试用例数量 t(1≤t≤10⁴);
每个测试用例的第一行包含 4 个整数 w、h、a、b(1≤w,h,a,b≤10⁹),分别表示屋顶尺寸和屋面板尺寸;
第二行包含 4 个整数 x₁、y₁、x₂、y₂(-a+1≤x₁,x₂≤w−1,-b+1≤y₁,y₂≤h−1),表示已放置屋面板的左下角坐标,且保证两块板不重叠。
输出格式
对每个测试用例,若能在保留已放置板的情况下完全覆盖屋顶,输出 “Yes”(不区分大小写),否则输出 “No”。

这是官方给的图,可能由这个图推出来的解法并非正解,或者根本就解不出来

样例

7
6 5 2 3
-1 -2 5 4 答案是Yes

4 4 2 2
0 0 3 1 答案是No

10 9 3 2
0 0 4 3 答案是No

10 9 3 2
0 0 6 3 答案是Yes

5 5 2 2
-1 -1 4 -1 答案是No

5 5 2 2
-1 -1 2 3 答案是Yes

7 8 2 4
0 0 0 5 答案是No

输出

Yes
No
No
Yes
No
Yes
No
**注意:

  • 1:以下的所有图中的两个橙色区域均为最开始不可移动的两块板。**
  • 2:x轴上上的长度统一称为长 y轴上的长度统一称为宽,不要考虑大小关系。

提示(想清楚每一个问题的答案,在往下面看其他问题)

  • 1:上面的图并非正解 需要自己画图去理解 找到铺板方法。
  • 2: 最让我们头疼的是哪个区域,老是这这个区域不能填满,哪里又是最容易铺板的区域,总是可以把这个区域铺满。
  • 3: 第一个图我们是不是如下图这样填就迎刃而解了?我们解决了哪一部分的铺板问题?为什么我们要优先解决这个区域的铺板问题?这个区域的铺板问题能否被解决与这个铺板问题具有什么关联关系(贪心)?
    -在这里插入图片描述
  • 4:为什么前面三个图都有解,而最后一个,无论我们怎么填总有空白区域?
  • 我想此时的你已经明白了,这个解法才是最优解。如果还没明白,下面将为您解答所有的疑惑。
    在这里插入图片描述

解析

  • 提示2的解析:其实最让我们头疼的一直都是不能移动的两块板 之间的区域(下图黑色区域),最容易的一直都是剩下没有染色的区域。在这里插入图片描述

  • 提示3的解析:第一个图我们就按照上图那样填,优先尝试能否将这个中间区域填满。如果解决了。那么整个问题就解决了,输出YES。如果没有解决,那么整个问题也就没有方案可以解决,输出NO。

  • 提示4的解析:提示4其实就是在问,我们怎么解决的中间区域的染色问题,有怎样的数学关系?
    我们总是可以发现 前三个图有解总是满足中间区域的长 模上 板的长等于0 或中间区域的宽 模上板的宽等于0这个条件即**(abs(x1 - x2) % a == 0 || abs(y1 - y2) % b == 0)**。那么不满足这个条件,则一定不能将房顶全部铺满板子,直接输出NO。看到这里是不是 恍然大悟!但别急,因为还没有大彻大悟!在满足这个条件下,还有可能不能将房顶铺满。请看下图
    在这里插入图片描述

此图的中间区域的宽模上板的宽同样是0但是我们无法找到解,同理长也是这样。但这个图与1号2号3号图的区别在于它的两个橙色房板在同一排。所以我们只需要在内部在特判一下,这两块橙色房板是否在某一方向对齐,对齐了的话,中间的区域能不能放完。至此,整个问题已经解决。

代码呈现

#include <iostream>
using namespace std;

int main() {
    int t;
    cin >> t;
    while (t--) {
        int w, h, a, b;
        cin >> w >> h >> a >> b;
        int x1, y1, x2, y2;
        cin >> x1 >> y1 >> x2 >> y2;
        if (abs(x1 - x2) % a == 0 || abs(y1 - y2) % b == 0) {//基本满足条件
            if (x1 == x2 && abs(y1 - y2) % b != 0 || y1 == y2 && abs(x1 - x2) % a != 0) {//如果  在纵向方向上对齐,中间的区域无法填满  或者  在横向方向上对齐,中间的区域无法填满
                cout << "NO" << endl;
            }
            else cout << "YES" << endl;
        }
        else cout << "NO" << endl;
    }
    return 0;   
}



  • 如果你足够聪明,你可以发现,这种填法是周期性填补,代码也是非常的简短!
  • 其思想非常类似贪心算法,试图用局部答案,结局全局答案!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值