[BZOJ 2299][HAOI 2011]向量 题解(裴蜀定理)

[BZOJ 2299][HAOI 2011]向量

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 (-2109<=a,b,x,y<=2109)

Output
t行每行为Y或者为N,分别表示可以拼出来,不能拼出来

Solution

1.考虑把八种情况合在一起,发现反向操作可以合并,那么操作也就是有四种(a,b),(-a,b),(b,a),(-b,a);

2.设四种操作进行的次数分别为x1,x2,x3,x4,那么:

对横坐标的操作为x1a-x2a+x3b-x4b,即(x1-x2)a+(x3-x4) b=x;

对纵坐标的操作为x1b+x2b+x3a+x4a,即(x1+x2)b+(x3+x4)a=y;

于是我们验证两方程是否有整数解即可。

3.裴蜀定理告诉我们:当gcd(a,b)|ans时,方程有整数解。

考虑四个系数的奇偶性,因为四个系数是四个数的组合,所以gcd应该是原来的二倍。

比如当x1-x2是奇数时,假设可行解中系数x1+x2为偶数,那就不成立了,所以我们分情况讨论之后发现,满足要求时gcd应该为原来的二倍。

Code

#include<iostream>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
typedef long long ll;
using namespace std;
 
ll g;
 
inline ll rd(){
    ll x=0; 
    bool f=0;
    char c=getchar();
    while(!isdigit(c)){
        if(c=='-')f=1;
        c=getchar();
    }
    while(isdigit(c)){
        x=(x<<1)+(x<<3)+(c^48);
        c=getchar();
    }
    return f?-x:x;
} 
 
ll gcd(ll x,ll y){return y?gcd(y,x%y):x;} 
 
bool valid(ll x,ll y){return (!(x%g))&&(!(y%g));}
 
int main(){
    ll t=rd();
    while(t--){
        ll a=rd(),b=rd();
        ll x=rd(),y=rd();
        g=gcd(a,b)<<1;
        printf((valid(x,y)||valid(x+a,y+b)||valid(x+b,y+a)||valid(x+a+b,y+a+b))?"Y\n":"N\n");
    }
    return 0;
} 
posted @ 2018-05-13 08:55 COLINGAO 阅读(...) 评论(...) 编辑 收藏