UVALive 4384 Business Cards

题目:
https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=2385

题意:
t t 组询问,每次询问能否用一些a×b的纸片拼成 c×d c × d 的纸片。
t105,1a,b,c,d109 t ≤ 10 5 , 1 ≤ a , b , c , d ≤ 10 9

题解:
有两种情况,一种是纸片全部按同一个方向放置,另一种是纸片按照两个方向放置。
第一种情况很容易检查,第二种情况必然存在一些平行的轴线能将不同方向放置的纸片分隔开,否则必然存在一些位置无法填满。(某人:这似乎是伪证;笔者:证明
考虑平行于轴线的方向,这条边的长度必须能整除 a a 也能整除b
考虑垂直于轴线的方向,这条边的长度必须是 a a b的线性组合,即长度是 ax+by a x + b y 的形式,并且 x,y0 x , y ≥ 0
不妨设垂直的这条边长度为 n n ,有解则必然(a,b)|n,利用扩展欧几里得算法可以得到一组解使得 ax+by=n a x ′ + b y ′ = n ,但是如果 ab a ≠ b ,那么 x,y x ′ , y ′ 之中有一个会小于0。
我们知道通解满足 {x=x+kb(a,b)y=yka(a,b) { x = x ′ + k b ( a , b ) y = y ′ − k a ( a , b ) ,那么只需要合理的设置 k k ,将小于0的那个系数恰好变正,检查另外一个系数能否非负即可,这个可以转化为询问一个区间里是否存在至少一个整数,可以O(1)解决。
于是每个询问就在 O(logmax(a,b)) O ( log ⁡ max ( a , b ) ) 的复杂度中解决了。

代码:

#include <cstdio>
typedef long long LL;
int t, a, b, c, d;
int exgcd(int a, int b, int &x, int &y)
{
    if(!b)
    {
        x = 1;
        y = 0;
        return a;
    }
    int r = exgcd(b, a % b, y, x);
    y -= a / b * x;
    return r;
}
bool check(int x, int a, int b)
{
    int s, t, r = exgcd(a, b, s, t);
    if(x % r)
        return 0;
    a /= r;
    b /= r;
    x /= r;
    LL xs = (LL)s * x, xt = (LL)t * x;
    if(xs < 0)
        return xt / a >= (-xs - 1) / b + 1;
    if(xt < 0)
        return xs / b >= (-xt - 1) / a + 1;
    return 1;
}
int main()
{
    scanf("%d", &t);
    while(t--)
    {
        scanf("%d%d%d%d", &a, &b, &c, &d);
        puts(c % a == 0 && d % b == 0
        || c % b == 0 && d % a == 0
        || c % a == 0 && c % b == 0 && check(d, a, b)
        || d % a == 0 && d % b == 0 && check(c, a, b) ? "YES" : "NO");
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值