题意很简单,很早就想做的题目,但一直由于对数论的恐惧= =,放下很久,现在才来看。于是就看了一下午...在Shangke7788的帮助下才弄明白。
首先我们先看扩展欧几里得算法:线性组合 ax+by=gcd(a, b)。
证明请看算法导论。
有一点要注意:对于x和y ,有无数种组合使得等式成立,利用 扩展欧几里得算法 求出来的只是任意一种解。
void exgcd(LL a,LL b,LL &x,LL &y,LL &d){
if (b==0){
x=1;
y=0;
d=a;
return ;
}
exgcd(b,a%b,y,x,d);
y-=a/b*x;
}
POJ1061 青蛙的约会
我们对方程做线性变换:k*(m-n)+p*L=y-x 。
假设m-n=a ,k=x,L=b,p=y 。得到 ax+by=gcd(a,b)
于是,我们 求出 d=gcd。判断 d是否整除y-x。
假设d|(y-x):因为 ax+by=d ,两边除以 d 得到 x*a‘+b*y’=1 ,a'=a/d , b'=b/d ,设 (y-x)/d=r ,得到 r*x*a'+r*y*b'=r 。
要得到最小正整数解,做变换: a'*(r*x+t*b')+b'*(r*y-t*a')=r ,t是任意整数,所以我们使 r*x%b' 便是最小正整数解。
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
#define LL long long
using namespace std;
//扩展欧几里得算法
void exgcd(LL a,LL b,LL &x,LL &y,LL &d){
if (b==0){
x=1;
y=0;
d=a;
return ;
}
exgcd(b,a%b,y,x,d);
y-=a/b*x;
}
int main(){
LL x,y,n,m,L,k,p,d;
while (~scanf("%lld%lld%lld%lld%lld",&x,&y,&m,&n,&L)){
exgcd(m-n,L,k,p,d);
if (m!=n&&(y-x)%d==0){
L=L/d;
k=k*((y-x)/d);
if (L<0) L=-L;//L可能为负数,在求最小正整数解的时候,%负数和%他的相反数结果相同
k=(k%L+L)%L;
printf("%lld\n",k);
}
else printf("Impossible\n");
}
return 0;
}