數論-裴蜀定理-Acwing-五指山
題目:
大聖在佛祖的手掌中。
我們假設佛祖的手掌是一個圓圈,圓圈的長爲 n,逆時針記爲:0,1,2,…,n−1,而大聖每次飛的距離爲 d。
現在大聖所在的位置記爲 x,而大聖想去的地方在 y。
要你告訴大聖至少要飛多少次才能到達目的地。
注意:孫悟空的筋斗雲只沿着逆時針方向翻。
輸入格式
有多組測試數據。
第一行是一個正整數 T,表示測試數據的組數;
每組測試數據包括一行,四個非負整數,分別爲如來手掌圓圈的長度 n,筋斗所能飛的距離 d,大聖的初始位置 x 和大聖想去的地方 y。
輸出格式
對於每組測試數據,輸出一行,給出大聖最少要翻多少個筋斗雲才能到達目的地。
如果無論翻多少個筋斗雲也不能到達,輸出 Impossible。
數據範圍
2<n<109,
0<d<n,
0≤x,y<n
輸入樣例:
2
3 2 0 2
3 2 0 1
輸出樣例:
1
2
題意:
給定一個圈,有n個點0,1,2,...,n−1。從起始位置x開始,每次可以移動d個點,問能否到達位置y,若能,輸出最小次數。
列出方程:x+bd≡y(modn),其中b=0,1,2,...。即求該方程中b的最小整數解。
上述方程可轉化爲:x+bd=y+an,a=0,1,2,...。
即:求n(−a)+db=y−x是否有整數解(−a,b)。
裴蜀定理:
若a,b是整數,且gcd(a,b)=d,那麼對於任意的整數x,y,ax+by都一定是d的倍數,特別地,一定存在整數x,y,使ax+by=d成立。
重要推論: a,b互質的充要條件是存在整數x,y使ax+by=1。
那麼若a,b互質,上述推論兩邊擴大任意倍,ax+by可以取到任意整數。
裴蜀定理的通解: 若ax0+by0=d,則方程ax+by=d的通解爲:{x=x0+kb′y=y0−ka′,其中k=1,2,...。a′=da,b′=db。
證明:{ax0+by0=dax+by=d,兩式相減,得a(x−x0)=b(y0−y),則a′(x−x0)=b′(y0−y),從而b′∣a′(x−x0)。
又因爲gcd(a′,b′)=1,所以b′∣(x−x0),所以x=x0+kb′。同理,y=y0−ka′。k=1,2,...。
所以知道一組特殊解,可以求得任意解。
擴展歐幾里得算法: ——遞歸求x0,y0
由gcd(a,b)=gcd(b,a%b),對方程ax+by=d也求其下一個狀態,等價於bx+(a%b)y=d,而bx+(a%b)y=bx+(a−b⌊ba⌋)y=ay+b(x−⌊ba⌋y)=d,得到解{x′=yy′=x−⌊ba⌋y
代碼:
int exgcd(int a,int b,int &x,int &y)
{
if(!b)
{
x=1;y=0;
return a;
}
int d=exgcd(b,a%b,x,y);
int temp=y;
y=x-(a/b)*y;
x=temp;
return d;
}
回到本題中,要求n(−a)+db=y−x是否有整數解(−a,b),就是要判斷是否存在m∣y−x,滿足n(−a)+db=m。即m是y−x的因子,可以方程兩邊同時擴大gcd(n,d)y−x得到n(−a)+db=y−x,得到的解就是b×gcd(n,d)y−x。
並且要求最小的次數b,我們知道若求出一組解b0,則b=b0+kgcd(n,d)n,則bmin=b0%gcd(n,d)n。
代碼:
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
ll exgcd(ll a,ll b,ll &x,ll &y)
{
if(!b)
{
x=1;y=0;
return a;
}
ll d=exgcd(b,a%b,x,y);
ll temp=y;
y=x-(a/b)*y;
x=temp;
return d;
}
int main()
{
int T;
scanf("%d", &T);
while (T -- )
{
ll n, d, x, y, a, b;
scanf("%lld%lld%lld%lld", &n, &d, &x, &y);
int gcd = exgcd(n, d, a, b);
if ((y - x) % gcd) puts("Impossible");
else
{
b *= (y - x) / gcd;
n /= gcd;
printf("%lld\n", (b % n + n) % n);
}
}
return 0;
}