bzoj1477: 青蛙的约会
传送门:http://www.lydsy.com:808/JudgeOnline/problem.php?id=1477
思路:扩展欧几里德求解同余方程。
设x步后碰面,初始位置为x0,y0。
那么就有x0+mx=y0+nx(mod L)
(m-n)x=y0-x0(mod L) //程序里要先把m-n变成正数,L已经是正数,不用变,负数模会有问题,这两步的等号是同余。
于是就可以把这个同余方程变为不定方程ax+by=c
(m-n+L*t)x+Ly=(y0-x0) modL
然后就是exgcd的事了。
exgcd是用来求ax+by=Gcd(a,b)的整数解的
借用gcd的思想
bx'+(a%b)y'=gcd(b,a%b)
只要把这个方程化为上一个方程的形式,那么我们就可以由下一层推出这一层的解。
于是有bx'+(a-(a/b)*b)y'=gcd(b,a%b)
ay'+b(x'-(a/b)y')=gcd(b,a%b)
gcd(b,a%b)=gcd(a,b)
所以x=y',y=(x'-(a/b)y')
递归的底层即当b=0时,显然,x=1,y=0是一组解。
于是我们就可以层层向上求出一组解
对于ax+by=c的求解可以先求出ax+by=gcd(a,b),然后将x,y扩大c/gcd(a,b)倍就可以了。
无解(整数解)就是c%gcd(a,b)!=0,
当Gcd(a,b)=1时//没有这个就会漏解
通解即为 x=x0+bt
y=y0-at
于是就可以求最小整数解之类的问题了
对于这道题,只要求出 (m-n+L*t)x+Ly=(y0-x0) mod L的最小整数解即可
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; typedef long long ll; ll x0,y0,m,n,L; ll exgcd(ll a,ll b,ll &x,ll &y){ if (b==0){x=1,y=0;return a;} int Z=exgcd(b,a%b,x,y),t=x; x=y,y=t-a/b*y;return Z; } int gcd(int a,int b){return !b?a:gcd(b,a%b);} int main(){ scanf("%lld%lld%lld%lld%lld",&x0,&y0,&m,&n,&L); ll A=((m-n)%L+L)%L,B=L,C=y0-x0,x,y,t=exgcd(A,B,x,y); if (C%t!=0){puts("Impossible");return 0;} A/=t,B/=t,C/=t,x=(x*C%B+B)%B; printf("%lld\n",x); return 0; }