说在前面
并没有什么想说的,但是要保持格式=w=
题目
题面
给你一对数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
可以发现,原来的八种向量,其实可以等价于以下几种操作:
- 对x或y,加上或减去2*a
- 对x或y,加上或减去2*b
- x+a,y+b
- 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" ) ;
}
}