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.四个全为偶数,则我们可以对方程组变换为

[afrac{Z_1}{2}+bfrac{Z_3}{2}=frac{x}{2} ]

[bfrac{Z_2}{2}+afrac{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
"); continue;}
		if(check(A, B, x + a) && check(A, B, y + b)) {printf("Y
"); continue;}
		if(check(A, B, x + b) && check(A, B, y + a)) {printf("Y
"); continue;}
		if(check(A, B, x + a + b) && check(A, B, y + a + b)) {printf("Y
"); continue;}
		printf("N
");
	}
	return 0;
}
原文地址:https://www.cnblogs.com/loi-frank/p/13904059.html