[BZOJ2299]-[HAOI2011]向量-裴蜀定理

说在前面

并没有什么想说的,但是要保持格式=w=


题目

BZOJ2299传送门

题面

给你一对数a,b,你可以任意使用(a,b), (a,-b), (-a,b), (-a,-b), (b,a), (b,-a), (-b,a), (-b,-a)这些向量,问你能不能拼出另一个向量(x,y)。
说明:这里的拼就是使得你选出的向量之和为(x,y)

输入输出格式

输入格式:
第一行一个整数T,表示数据组数(T≤50000)
接下来每行一组数据,包含四个整数a,b,x,y

输出格式:
对于每组数据,输出一行:
如果可以输出Y,不行则输出N


解法1

如果只用前四个向量,那么只能凑出来 (u1 a,u2 b) ( u 1   a , u 2   b ) 这样的向量;如果只用后四个,也只能 (v1 b,v2 a) ( v 1   b , v 2   a ) 这样的向量。因此,前四个向量和后四个向量 是独立的,它们互不干扰
那么假设前四个的贡献是 (u1 a,u2 b) ( u 1   a , u 2   b ) ,后四个的贡献是 (v1 b,v2 a) ( v 1   b , v 2   a ) ,那么可以列出方程: {u1a+v1b=xu2b+v2a=y { u 1 a + v 1 b = x u 2 b + v 2 a = y ,其中要求 u1,u2 u 1 , u 2 奇偶一致, v1,v2 v 1 , v 2 奇偶一致(因为单组内a和b的个数差始终是2的倍数)

那么枚举u和v的奇偶性即可,然后用x和y减去奇数多出来的那一个,那么如果有一组偶数解u,v,那么此题有解。
不妨把x和y都除以二,那么这样限制就没有了,直接用裴蜀定理判定即可。(裴蜀:ax+by=c有解当且仅gcd(a,b)|c)

解法2

可以发现,原来的八种向量,其实可以等价于以下几种操作:

  1. 对x或y,加上或减去2*a
  2. 对x或y,加上或减去2*b
  3. x+a,y+b
  4. x+b,y+a

而且第3,4种操作,最多用一次。(超过两次的部分可以替换成1或2操作)
于是枚举用没有用3,4操作,如果用了就减掉,之后也是裴蜀定理判断


下面是代码

两种方法其实是差不多的,代码也毫无区别

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

int T ;
long long a , b , x , y , d ;

long long gcd( long long a , long long b ){
    return !b ? a : gcd( b , a%b ) ;
}
bool check( long long x , long long y ){
    if( x&1 || y&1 ) return false ;
    return ( x>>1 )%d == 0 && ( y>>1 )%d == 0 ;
}
int main(){
    scanf( "%d" , &T ) ;
    while( T -- ){
        scanf( "%lld%lld%lld%lld" , &a , &b , &x , &y ) ;
        d = gcd( a , b ) ;
        if( check( x-a, y-b ) || check( x-b , y-a ) || check( x , y ) || check( x-a-b , y-a-b ) )
            puts( "Y" ) ;
        else puts( "N" ) ;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值