天天看點

URAL 1286

//此題網上有人已經寫過解釋,但我認為太過敷衍,沒有挖掘内在的實質。甚至可以認為某些叙述就是毫無根據。

題目大意:判斷坐标(x2,y2)能不能由(x1(+/-)m,y1(+/-)n)或者(x1(+/-)n,y(+/-)m)這八種操作得到。

Time Limit:1000MS     Memory Limit:65536KB     64bit IO Format:%I64d & %I64u

資料規模:-2^9<=x1,x2,y1,y2,m,n<=2^9,且均為整數。

理論基礎:裴蜀定理:對任意兩個整數a、b,設d是它們的最大公約數。那麼關于未知數x和y的線性丢番圖方程(稱為裴蜀等式):ax+by=m有整數解(x,y),當且僅當m 是d 的倍數。

題目分析:由于每個數都是整數,是以這是一個基于單元格點的可達性的問題,和數論有什麼聯系呢?仔細觀察,你會發現,我們将初始坐标變為(0,0),終止坐标變為(x,y)(x=abs(x1-x2),y=abs(y1-y2)),記gcd=gcd(m,n)。

首先,如果x%gcd!=0或者y%d!=0,那麼肯定無解,因為兩個不等于零會導緻:x=m*a+n*b或者y=m*a+n*b方程無整數解(裴蜀定理)。

其次,如果x%gcd==0,y%gcd==0。我們令:x/=gcd,y/=gcd,m/=gcd,n/=gcd。

原問題依舊為能否至(x,y),但此時m,n互質,且不可能全為偶數。是以:用m和n可以表示任何整數。因為:a*m+b*n=1有解,其它整數都是1的倍數。

首先,我們如果用題目給的(+/-m,+/-n)分析的話,考慮太多,因為湊成x的時候,y也就随之确定。無法更改。而且我們讨論的解是整數解,本身帶有正負,是以我們先由已知衍生出這樣的操作:(2*m,0),(2*n,0)還有對稱的兩組這裡就不再寫了。那麼由前兩種操作我們可以得出所有的(2*a,2*b)的點都可達,因為:2*(x*m+n*y=a or b)總是有整數解的。即(2*a or 2*b,0)可以由x種(2*m,0),y種(2*n,0)得來。由對稱性我們可以得到:(2*a,2*b)是可達的。

然後,我們就可以将剩下的所有點變為:讨論(1,0)(與(0,1)相同),(1,1)是否可達的情況,也就是說其它的點都是由偶數坐标(2*a,2*b)+(1,0) or (0,1) or (1,1)衍生而來。

那麼,我們可以得出:(1,0)當m,n為一奇一偶是可達的,不妨假設m為奇數,n為偶數。因為:m*x+n*y=1肯定有解(上面說了n次了,好累

URAL 1286

),但此時的解我們選:x為奇數,y為偶數(原方程有無數組解,這種解是存在的)。那麼此時對應的對于縱坐标的操作:x*n+y*m就是偶數了。也就是說可以通過已知的證明(0,2*a)變為0了。是以當m,n一奇一偶時,是可達的,相反,全為奇數時是不可達的。因為解x,y一奇一偶無論選哪種,x*n+y*m都是奇數。不能變為0。(0,1)同理可證。

最後,我們讨論(1,1),(1,1)是任意可達的。因為當m,n一奇一偶時:m*x+n*y=1的解中我們可以選:x為奇數,y為奇數。這樣:x*n+y*m就是奇數了。這是消去小于它的最大偶數就可以得到(1,1)了。當m,n均為奇數時:m*x+n*y=1的解為一奇一偶。那麼:x*n+y*m也就肯定是奇數了,消去小于它的最大偶數就可以的到(1,1)了。

綜上,當x or y任意一個不被gcd(m,n)整除時,不可達。皆可被gcd整除時,當x,y同為奇數或同為偶數時,任意可達。當x,y一奇一偶時,當且僅當m,n一奇一偶可達。

呼呼,可算是完了。。。好累啊。推了半天。

代碼如下:

#include<iostream>
#include<cstring>
#include<string>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<queue>
using namespace std;
typedef double db;
#define DBG 1
#define maa (1<<31)
#define mii ((1<<31)-1)
#define sl(c) ((int)(c).size())    //取字元串長度;
#define forl(i, a, b) for(int i = (a); i <  (b); ++i)    //不帶邊界值循環,正序
#define forle(i, a, b) for(int i = (a); i <= (b); ++i)   //帶邊界值循環,正序
#define forh(i, a, b) for(int i = (a); i >  (b); --i)     //不帶邊界值,逆序
#define forhe(i, a, b) for(int i = (a); i >= (b); --i)        //帶邊界值,逆序
#define forlc(i, a, b) for(int i##_b = (b), i = (a); i <  i##_b; ++i)  //帶别名的循環,用于不可改變值
#define forlec(i, a, b) for(int i##_b = (b), i = (a); i <= i##_b; ++i)
#define forgc(i, a, b) for(int i##_b = (b), i = (a); i >  i##_b; --i)
#define forgec(i, a, b) for(int i##_b = (b), i = (a); i >= i##_b; --i)
#define forall(i, v   )  forl(i, 0, sz(v))   //循環所有
#define forallc(i, v   ) forlc(i, 0, sz(v))
#define forlla(i, v   ) forhe(i, sz(v)-1, 0)
#define forls(i, n, a, b) for(int i = a; i != b; i = n[i])   //搜表用
#define rep(n)  for(int               repp = 0; repp <    (n); ++repp)
#define repc(n) for(int repp_b = (n), repp = 0; repp < repp_b; ++repp)
#define rst(a, v) memset(a, v, sizeof a)   //把字元v填充到a  reset 重置
#define cpy(a, b) memcpy(a, b, sizeof a)   //copy b 的sizeof(a)個字元到a
#define rstn(a, v, n) memset(a, v, (n)*sizeof((a)[0]))  //把字元v填充到a[n]之前的位元組
#define cpyn(a, b, n) memcpy(a, b, (n)*sizeof((a)[0]))    //copy b 的 n 個字元到a
#define ast(b) if(DBG && !(b)) { printf("%d!!|\n", __LINE__); while(1) getchar(); }  //調試
#define dout DBG && cout << __LINE__ << ">>| "
#define pr(x) #x"=" << (x) << " | "
#define mk(x) DBG && cout << __LINE__ << "**| "#x << endl
#define pra(arr, a, b)  if(DBG) {\
    dout<<#arr"[] |" <<endl; \
    forlec(i, a, b) cout<<"["<<i<<"]="<<arr[i]<<" |"<<((i-(a)+1)%8?" ":"\n"); \
    if((b-a+1)%8) puts("");\
}                                                             //數列檢視
#define rd(type, x) type x; cin >> x   //讀數
inline int     rdi() { int d; scanf("%d", &d); return d; }
inline char    rdc() { scanf(" "); return getchar(); }
inline string  rds() { rd(string, s); return s; }
inline db rddb() { db d; scanf("%lf", &d); return d; }
template<class T> inline bool updateMin(T& a, T b) { return a>b? a=b, true: false; }
template<class T> inline bool updateMax(T& a, T b) { return a<b? a=b, true: false; }

inline long long gcd(long long a,long long b)
{
    long long c;
    while (b)
    {
        c=a%b;
        a=b;
        b=c;
    }
    return a;
}

int main()
{
    long long p,q,x0,y0,x1,y1,x,y,d;
    scanf("%I64d%I64d%I64d%I64d%I64d%I64d",&p,&q,&x0,&y0,&x1,&y1);
    x=abs(x1-x0);
    y=abs(y1-y0);
    d=gcd(p,q);
    if ((!p) && (!q))
    {
        if ((!x) && (!y))  printf("YES\n");
        else    printf("NO\n");
        return 0;
    }
    if ((x%d) || (y%d))
    {
        printf("NO\n");
        return 0;
    }
    x/=d,y/=d,p/=d,q/=d;
    if (((p&1)^(q&1)) || ((x&1)^(y&1)^1))
        printf("YES\n");
    else   printf("NO\n");
    return 0;
}
           

其中:n&1的值就是判斷n是否為偶數,若為偶數,n&1值為0,若為奇數,n&1值為1。

參考文獻:

http://zh.wikipedia.org/wiki/%E8%A3%B4%E8%9C%80%E5%AE%9A%E7%90%86

by:Jsun_moon http://blog.csdn.net/jsun_moon