Description
给你一对数a,b,你可以任意使用(a,b), (a,-b), (-a,b), (-a,-b), (b,a), (b,-a), (-b,a), (-b,-a)这些向量,问你能不能拼出另一个向量(x,y)。
说明:这里的拼就是使得你选出的向量之和为(x,y)
Input
第一行数组组数t,(t<=50000)
接下来t行每行四个整数a,b,x,y (-2*10^9<=a,b,x,y<=2*10^9)
Output
t行每行为Y或者为N,分别表示可以拼出来,不能拼出来
Sample Input
3
2 1 3 3
1 1 0 1
1 0 -2 3
Sample Output
Y
N
Y
HINT
样例解释:
第一组:(2,1)+(1,2)=(3,3)
第三组:(-1,0)+(-1,0)+(0,1)+(0,1)+(0,1)=(-2,3)
Solution:
首先8种向量只有四个本质不同的向量。
我们设有 k1(a,b),k2(a,−b),k3(b,a),k4(b,−a) ,
那么我们有 a(k1+k2)+b(k3+k4)=x , a(k3−k4)+b(k1−k2)=y ,我们记 p1=k1+k2,p2=k3+k4,p3=k3−k4,p4=k1−k2 ,那么 k1,k2,k3,k4 有整数解的条件是 p1≡p4(mod2),p2≡p3(mod2) ,我们用拓展欧几里得接出 p1,p2,p3,p4 的一组解,显然 mod2 将每一个不定方程分为两类,一共四种情况,一一判断即可
Code :
/************************************************************************* > File Name: bzoj2299.cpp > Author: Archer ************************************************************************/
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
inline ll read(){
ll x = 0, f = 1; char ch = getchar();
while (!isdigit(ch)) {if (ch == '-') f = -1; ch = getchar();}
while (isdigit(ch)) {x = x * 10ll + ch - '0'; ch = getchar(); }
return f == 1 ? x : -x;
}
inline void exgcd(ll a, ll &x, ll b, ll &y){
if (b == 0) {x = 1ll; y = 0ll; return;}
ll x1, y1; exgcd(b, x1, a % b, y1);
x = y1; y = x1 - a / b * y1;
}
inline ll gcd(ll a, ll b) {return b == 0 ? a : gcd(b, a % b);}
inline bool check(ll p1, ll p2, ll p3, ll p4){
return (((p1-p4)%2 == 0) && ((p2-p3)%2 == 0));
}
int main(){
for (ll T = read(); T--;){
ll a = read(), b = read(), x = read(), y = read();
if (a < b) swap(a, b);
if (a == 0) {puts(x == 0 && y == 0 ? "Y" : "N"); continue;}
ll d = gcd(a, b); ll p1, p2, p3, p4, d1 = b / d, d2 = a / d;
if (x % d != 0 || y % d != 0) {puts("N"); continue;}
ll t1, t2; exgcd(a / d, t1, b / d, t2);
p1 = t1 * x / d; p2 = t2 * x / d;
p3 = t1 * y / d; p4 = t2 * y / d;
if (check(p1, p2, p3, p4) || check(p1 + d1, p2 - d2, p3, p4)
||check(p1, p2, p3 + d1, p4 - d2) || check(p1 + d1, p2 - d2, p3 + d1, p4 - d2)) puts("Y");
else puts("N");
}
return 0;
}