题目传送门:http://hihocoder.com/problemset/problem/1297
扩展欧几里德(exgcd)我一直学的不是太好,虽然中间的一些道理啊知道,但是每次碰到exgcd的题就都不会写,正负错啊,模错啊
今天小小总结下我自己的exgcd的经验把,不是讲原理,因为原理大家都看过很多,反正我记不住,套套模板就好了
首先一般都是构造ax+by=c,然后调用exgcd(a,b,d,x,y),求出d,x,y,如果c%d!=0时无解,如果题目让你求x,那么a=0时也是无解,下面以只求x为例
然后就是此时求出来的x是ax+by=d的解,要变成ax+by=c的解,还需要x=x*(c/d),此时是一个解
那么通解形式是啥样呢,x=x+(b/d)*t ,y=y-(a/d)*t;记住即可
所以如果你要求x的最小值,x是关于t的单调函数,根据(b/d)的正负性,取值即可
一般题目做到x都是大于等于0的,所以这里就说下x>=0时最小值怎么求
x>=0时,肯定是减去越多的abs(b/d)越好,所以x%abs(b/d),但是可能原来x用exgcd求解出来是负数,所以就加上abs(b/d),再模一下
所以答案ans=(x%abs(b/d)+abs(b/d))%abs(b/d);
这里以hiho一下的例题为例。
小Hi和小Ho周末在公园溜达。公园有一堆围成环形的石板,小Hi和小Ho分别站在不同的石板上。已知石板总共有m块,编号为 0..m-1,小Hi一开始站在s1号石板上,小Ho一开始站在s2号石板上。
小Hi:小Ho,你说我们俩如果从现在开始按照固定的间隔数同时同向移动,我们会不会在某个时间点站在同一块石板上呢?
小Ho:我觉得可能吧,你每次移动v1块,我移动v2块,我们看能不能遇上好了。
小Hi:好啊,那我们试试呗。
一个小时过去了,然而小Hi和小Ho还是没有一次站在同一块石板上。
小Ho:不行了,这样走下去不知道什么时候才汇合。小Hi,你有什么办法算算具体要多久才能汇合么?
小Hi:让我想想啊。。
提示:扩展欧几里德
第1行:每行5个整数s1,s2,v1,v2,m,0≤v1,v2≤m≤1,000,000,000。0≤s1,s2<m
中间过程可能很大,最好使用64位整型
第1行:每行1个整数,表示解,若该组数据无解则输出-1
0 1 1 2 6
5
假设时间t,小hi走到了(s1+v1*t)%m的位置,小ho走到了(s2+v2*t)%m的位置,然后这两个位置相同
(s1+v1*t)%m=(s2+v2*t)%m => s1+v1*t +m*a = s2+v2*t => (v1-v2)*t+m*a=s2-s1
这不就是我们exgcd的形式么,然后带入exgcd(v1-v2,m,d,x,y),求出d,x,y
如果(s2-s1)%d!=0||v1==v2 ,输出-1
否则就是构造最小解,x=x*(s2-s1)/d, x=(x%abs(m/d)+abs(m/d))%abs(m/d);
#include <map> #include <set> #include <stack> #include <queue> #include <cmath> #include <string> #include <vector> #include <cstdio> #include <cctype> #include <cstring> #include <sstream> #include <cstdlib> #include <iostream> #include <algorithm> #pragma comment(linker,"/STACK:102400000,102400000") using namespace std; #define MAX 5000005 #define MAXN 100005 #define maxnode 10 #define sigma_size 2 #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 #define lrt rt<<1 #define rrt rt<<1|1 #define middle int m=(r+l)>>1 #define LL long long #define ull unsigned long long #define mem(x,v) memset(x,v,sizeof(x)) #define lowbit(x) (x&-x) #define pii pair<int,int> #define bits(a) __builtin_popcount(a) #define mk make_pair #define limit 10000 //const int prime = 999983; const int INF = 0x3f3f3f3f; const LL INFF = 0x3f3f; const double pi = acos(-1.0); const double inf = 1e18; const double eps = 1e-9; const LL mod = 1e9+7; const ull mxx = 1333331; /*****************************************************/ inline void RI(int &x) { char c; while((c=getchar())<'0' || c>'9'); x=c-'0'; while((c=getchar())>='0' && c<='9') x=(x<<3)+(x<<1)+c-'0'; } /*****************************************************/ void exgcd(LL a,LL b,LL &d,LL &x,LL &y){ if(!b){x=1;y=0;d=a;return;} else {exgcd(b,a%b,d,y,x);y-=a/b*x;} } LL labs(LL a){ if(a<0) return -a; return a; } int main(){ //freopen("in.txt","r",stdin); LL s1,s2,v1,v2,m; cin>>s1>>s2>>v1>>v2>>m; LL x,y,d; exgcd(v1-v2,m,d,x,y); if((s2-s1)%d!=0||v1==v2) printf("-1\n"); else{ x=x*(s2-s1)/d; LL mo=labs(m/d); cout<<(x%mo+mo)%mo<<endl; } return 0; }