AcWing1299. 五指山
扩展欧几里得算法可以解决裴蜀定理
- 所有解的形式是什么
- 为什么一定是这种形式,可以使用反证法或者正推
首先我们要转化成一个同余方程:
\(x+a*d\equiv y\pmod n\)
然后展开:
\(x+a*d=b*n+y\)
把它转换成扩展欧几里得的形式:
\(a*d-b*n=y-x\)
然后运用扩展欧几里得算法算出\(a\)的一个解(扩展\((y-x)/gcd(d, n)\)倍)
算出一个解之后。根据紫书的定理。我们可以得出
最小正整数解为:
五指山那一题要求\(x = x_0 + k(\frac{n}{gcd(n,d)})\)的最小正整数,为什么是通过\((x_0 \% \frac{n}{gcd(n,d)} + \frac{n}{gcd(n,d)}) \% \frac{n}{gcd(n,d)})\)来求呢?
- 原理:不论\(x_0\)是个多大或者多小的一个数字,它通过\(k*\frac{n}{gcd(n,d)}\)都能把这个数缩小到\(0 -\frac{n}{gcd(n,d)}\)之间
- 因为这个\(x_0\)经过任意变换之后都能在\(0 -\frac{n}{gcd(n,d)}\)之间,所以我们求拿\(x_0\)对\(\frac{n}{gcd(n,d)}\)取正余数就好了
y总代码
#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, y, x);
y -= a / b * x;
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;
}
自己的代码
记得写longlong因为题目是\(x*10^9\)相乘很容易爆int
#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, y, x);
y = y - a / b * x;
return d;
}
int main()
{
int t;
cin >> t;
while(t--)
{
LL n, d, x, y;
LL a, b;
cin >> n >> d >> x >> y;
LL gcd = exgcd(d, n, a, b);
if((y - x) % gcd != 0) cout << "Impossible" << endl;
else
{
a = a * (y - x) / gcd;
LL t = n / gcd;
printf("%d\n", (a % t + t) % t);
}
}
return 0;
}