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\)分别为八个组成向量的个数,故有等式

\[a(X_1+X_2-X_3-X_4)+b(X_5+X_6-X_7-X_8)=x \]

\[b(X_1-X_2+X_3-X_4)+a(X_5-X_6+X_7-X_8)=y \]

\[Y_1=X_1-X_4,Y_2=X_2-X_3 \]

\[Y_3=X_5-X_8,Y_4=X_6-X_7 \]

再令

\[Z_1=Y_1+Y_2,Z_2=Y_1-Y_2 \]

\[Z_3=Y_3+Y_4,Z_4=Y_3-Y_4 \]

则原方程组变为

\[aZ_1+bZ_3=x \]

\[bZ_2+aZ_4=y \]

我们想知道的是,是否存在整数解,使得原方程组成立。我们想到用裴蜀定理去判别,但是经过进一步观察我们发现并不是简单的用裴蜀定理判断就行的,因为就\(Z_1,Z_2\)而言,有

\[Z_1=Y_1+Y_2,Z_2=Y_1-Y_2 \]

推出

\[Y_1=\frac 12(Z_1+Z_2),Y_2=\frac 12(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.四个全为偶数,则我们可以对方程组变换为

\[a\frac{Z_1}{2}+b\frac{Z_3}{2}=\frac{x}{2} \]

\[b\frac{Z_2}{2}+a\frac{Z_4}{2}=\frac{y}{2} \]

此时,由于四个数全为偶数,则\(\frac{Z_1}{2},\frac{Z_2}{2},\frac{Z_3}{2},\frac{Z_4}{2}\)可以取遍所有整数,这时候我们就可以运用裴蜀定理知,存在解的条件是

\[gcd(a,b)|\frac x2,gcd(a,b)|\frac y2 \]

\[gcd(2a,2b)|x,gcd(2a,2b)|y \]

2.四个数中\(Z_1,Z_2\)为偶,\(Z_3,Z_4\)为奇

我们对方程组进一步变换,第一行的等式两边同时加b,第二行加a,则变为

\[aZ_1+b(Z_3+1)=x+b \]

\[bZ_2+a(Z_4+1)=y+a \]

此时\(Z_3+1,Z_4+1\)为偶,情况又化归为第一种,我们可以直接算,得到条件是

\[gcd(2a,2b)|x+b,gcd(2a,2b)|y+a \]

3.四个数中\(Z_3,Z_4\)为偶,\(Z_1,Z_2\)为奇

同第二种。条件是

\[gcd(2a,2b)|x+a,gcd(2a,2b)|y+b \]

4.四个全为奇数

我们对两个方程两边都加a+b,这样又化归为第一种情况,条件是

\[gcd(2a,2b)|x+a+b,gcd(2a,2b)|y+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;
}
posted @ 2020-10-30 20:21  Frank喵^_^  阅读(66)  评论(0编辑  收藏  举报