【二元不定方程】POJ 青蛙的约会
首先,根据题意,我们可以列出同余方程:
( x + k m ) % L = = ( y + k n ) % L (x+km) \% L= = (y+kn)\%L (x+km)%L==(y+kn)%L
( x + k m ) − ( y + k n ) = a L (x+km)-(y+kn)=aL (x+km)−(y+kn)=aL
(
m
−
n
)
k
+
y
−
x
=
a
L
(m-n)k+y-x=aL
(m−n)k+y−x=aL
这就是一个二元一次不定方程了
可以直接套用exgcd
剩下的有一点点麻烦
题目要求最小的正整数k 所以我们还要找符合条件的这个特解
首先用exgcd搞一个特解出来
利用exgcd解
a
x
+
b
y
=
c
,
d
=
(
a
,
b
)
ax+by=c,d=(a,b)
ax+by=c,d=(a,b)的结论,我们知道x的通解是
x
+
b
d
x+\frac{b}{d}
x+db
在这个解为正整数的条件下 对于每一个解,我们可以快速求出最小正整数解为
(
x
+
b
d
)
%
b
d
(x+\frac{b}{d})\%\frac{b}{d}
(x+db)%db
[可以想成通解是一个等差数列,是最小的那个数加上很多个
b
d
\frac{b}{d}
db 构成的 所以每个解求余
b
d
\frac{b}{d}
db就是原来那个最小解]
所以在用exgcd求出解后 如果特解是负数 我们一直加 b d \frac{b}{d} db知道它为正 就是最小正整数解
如果求出的解本身为正 我们就求余 b d \frac{b}{d} db,就是答案
#include<cstdio>
#include<stack>
#include<cstring>
using namespace std;
#define MAXN 1005
#define LL long long
LL gcd(LL a,LL b)
{
return b?gcd(b,a%b):a;
}
void exgcd(LL a,LL b,LL &d,LL &x,LL &y)
{
LL x0=x,y0=y;
if(b==0)
{
d=a,x=1,y=0;
return ;
}
else
{
exgcd(b,a%b,d,x0,y0);
x=y0;
y=x0-a/b*y0;
}
}
int main()
{
LL x,y,m,n,l;
scanf("%lld %lld %lld %lld %lld",&x,&y,&m,&n,&l);
LL a=m-n,b=l,c=y-x;
if(a<0) a+=l;//把a变成正数 由于是环形 相对位置不改变 不影响结果
LL d=gcd(a,b);
if(c%d!=0)
{
printf("Impossible\n");
return 0;
}
exgcd(a,b,d,x,y);
x=x*(c/d);
while(x<0)
x+=(b/d);
x=x%(b/d);
printf("%lld\n",x);
return 0;
}
另外就是注释的地方 相当于确保a为整数
不知为什么加了这个东西就要快很多 当然加不加在poj上都还是可以过
此题在HihoCoder上也有一个比较相似的题目,可以了解一下 感觉这个网站上的提示还比较到位 有循循善诱的感觉
传送门