HAOI2011 向量
题目描述
给你一对数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)
接下来t行每行四个整数a,b,x,y (-2*109<=a,b,x,y<=2*109)
输出格式
t行每行为Y或者为N,分别表示可以拼出来,不能拼出来
输入输出样例
输入 #1复制
3
2 1 3 3
1 1 0 1
1 0 -2 3
输出 #1复制
Y
N
Y
说明/提示
样例解释:
第一组:(2,1)+(1,2)=(3,3)
第三组:(-1,0)+(-1,0)+(0,1)+(0,1)+(0,1)=(-2,3)
思路:本质上不算是一道很难的题(可是我实在是不擅长数论)。第一眼看上去好像没啥规律,果断用笨方法。设\(X_1,X_2,X_3...X_8\)分别为八个组成向量的个数,故有等式
令
再令
则原方程组变为
我们想知道的是,是否存在整数解,使得原方程组成立。我们想到用裴蜀定理去判别,但是经过进一步观察我们发现并不是简单的用裴蜀定理判断就行的,因为就\(Z_1,Z_2\)而言,有
推出
而\(Y_1,Y_2\)为任意整数,故\(Z_1+Z_2\)为偶数,\(Z_1-Z_2\)为偶数,所以\(Z_1\)和\(Z_2\)奇偶性相同。
同理我们也可以得到\(Z_3\)和\(Z_4\)奇偶性也相同。
故我们有四种情况:
1.四个全为偶数,则我们可以对方程组变换为
此时,由于四个数全为偶数,则\(\frac{Z_1}{2},\frac{Z_2}{2},\frac{Z_3}{2},\frac{Z_4}{2}\)可以取遍所有整数,这时候我们就可以运用裴蜀定理知,存在解的条件是
即
2.四个数中\(Z_1,Z_2\)为偶,\(Z_3,Z_4\)为奇
我们对方程组进一步变换,第一行的等式两边同时加b,第二行加a,则变为
此时\(Z_3+1,Z_4+1\)为偶,情况又化归为第一种,我们可以直接算,得到条件是
3.四个数中\(Z_3,Z_4\)为偶,\(Z_1,Z_2\)为奇
同第二种。条件是
4.四个全为奇数
我们对两个方程两边都加a+b,这样又化归为第一种情况,条件是
只要这四个条件成立其一,原问题就有解,否则无解。
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;//simplify long long
typedef unsigned long long ull;
typedef double db;
typedef long double ldb;
#define inf 2147483647
#define pi 3.14159265358979
#define rep(i, l, r) for(int i = l; i <= r; i ++)
#define lop(i, r, l) for(int i = r; i >= l; i --)
#define step(i, l, r, __step) for(int i = l; i <= r; i += __step)
#define revp(i, r, l, __step) for(int i = r; i >= l; i -= __step)
#define regsiter reg
#define regsiter int RI
#define regsiter long long RL
#define __int128 i8
#define i8 ll//don't forget delete it in contest!
inline ll read()//fast read
{
ll ret = 0, sgn = 1;
char chr = getchar();
while(chr < '0' || chr > '9')
{if(chr == '-') sgn = -1; chr = getchar();}
while(chr >= '0' && chr <= '9')
{ret = ret * 10 + chr - '0'; chr = getchar();}
return ret * sgn;
}
i8 write(i8 x)//int128's output
{
if(x < 0) putchar('-'), x = -x;
if(x > 9) write(x / 10);
putchar(x % 10 + '0');
}
const int N = 1e5 + 5;
const int M = 2e5 + 5;
ll gcd(ll a, ll b)
{
if(!b) return a;
return gcd(b, a % b);
}
inline bool check(ll a, ll b, ll d)
{
return !(d % gcd(a, b));
}
int main()
{
int T;
scanf("%d", &T);
ll a, b, x, y;
ll A, B;
while(T --)
{
a = read(), b = read(), x = read(), y = read();
A = a * 2, B = b * 2;
if(check(A, B, x) && check(A, B, y)) {printf("Y\n"); continue;}
if(check(A, B, x + a) && check(A, B, y + b)) {printf("Y\n"); continue;}
if(check(A, B, x + b) && check(A, B, y + a)) {printf("Y\n"); continue;}
if(check(A, B, x + a + b) && check(A, B, y + a + b)) {printf("Y\n"); continue;}
printf("N\n");
}
return 0;
}