数论之扩展欧几里德相关模板
拓展欧几里得公式:
typedef long long LL; LL exgcd(LL a,LL b,LL &x,LL &y){ if(a==0&&b==0) return -1; if(b==0) { x=1;y=0; return a; } LL d=exgcd(b,a%b,y,x); y-=a/b*x; return d; }
解ax+by=c的解集:
typedef long long LL; LL x0,y0,kx,ky; bool LE(LL a,LL b,LL c){ //解线性方程ax+by=c LL x1,y1; LL gcd=exgcd(a,b,x1,y1); if(c%gcd) return false; //无整数解 x0=x1*c/gcd; //一组解 y0=y1*c/gcd; //一组解 kx=b/gcd; ky=-a/gcd; return true; //有解,解集为:(x0+kx*t,y0+ky*t) t为整数 }
求解x的最小正整数解:
/* 求解出x的最小正整数解*/ typedef long long ll; void minxx(int a, int b, int c, int x, int y) { int gcd = exgcd(a, b, x, y); ll x1, y1, t; t = b / gcd; if( t<0 ) { t = -t; } x1 = (x+t)*(c/gcd); x1 = (x1%t+t)%t; y1 = (c-a*x1)/b; printf("x==%lld, y=%lld\n", x1, y1); return ; }
void minxx(ll a, ll b, ll c, ll x, ll y) { int gcd = exgcd(a, b, x, y); ll x1, y1, t; t = b / gcd; if( t<0 ) { t = -t; } x1 = x; x1 = (c/gcd*x1%t+t)%t; y1 = (c-a*x1)/b; printf("%lld %lld\n", x1, y1); return ; }
同余方程 ax≡b (mod n)对于未知数 x 有解,当且仅当 gcd(a,n) | b(即b%gcd(a, b)==0 ),且方程有解时,方程有 gcd(a,n) 个解。
求解方程 ax≡b (mod n) 相当于求解方程 ax+ ny= b, (x, y为整数)
求解线性同余方程:
bool modular_linear_equation(int a,int b,int n) { int x,y,x0,i; int d=exgcd(a,n,x,y); if(b%d) return false; x0=x*(b/d)%n; //特解 for(i=1;i<d;i++) printf("%d\n",(x0+i*(n/d))%n); return true; }
同余方程ax≡b (mod n),如果gcd(a, n)==1, 则方程只有唯一解。
这种情况下,如果b==1,同余方程就是ax=1(mod n), gcd(a, n)=1.
这时称求出的x为a的对模n乘法的逆元。
对于同余方程ax=1(mod n), gcd(a, n)=1 的求解就是求解方程ax+ny=1, x, y 为整数。
ll inv(ll a, ll n) { ll d, x, y; d = exgcd(a, n, x, y); return (d==1)?(x%n+n)%n:-1; }