gcd lcm 扩展欧几里得 逆元

(a+b)%p = ( a%p+b%p) % p

加法,减法,乘法 可以用,除法不可,转化成乘法,用逆元


板子1. 求得x,y使得 ax+by=gcd(a,b),返回ans为最大公因数

//求得x,y使得 ax+by=gcd(a,b),返回ans为最大公因数
例如 exgcd(5,7,x,y),运行后x=3,y=-2,ans=1;

ll exgcd(ll a,ll b,ll &x,ll &y){
	if(!b){
	x=1;y=0;return a;
	}else {
		ll ans = exgcd(b,a%b,x,y);
		ll temp=x;
		x=y;
		y=temp-a/b*y;
		return ans;
	}
}

板子2.求逆元 a关于m的逆元x,即a*x mod m==1

//ax = 1(mod n)
long long mod_reverse(long long a,long long n)
{
    long long x,y;
    long long d=extend_gcd(a,n,x,y);
    if(d==1) return (x%n+n)%n;
    else return -1;
}

板子2.求逆元 费马小定理

a的m-2次就是a关于m的逆元

ll quick_pow(ll a, ll b){
	if(b < 0) return 0;
	ll ret = 1;
	 a %= MOD;
	 while(b){
	 	if( b & 1) ret = (ret * a) % MOD;
	 	b >>= 1;
	 	a = (a * a) % MOD;
	 }
	 return ret;
}
ll inv(ll a,ll m){
	return quick_pow(a,m - 2);
}

例题

zoj3609

求最小的x满足 ax≡1 (mod m)

a=3,m=11,则x=4;


const int MAXN=2550;
const int MOD=9973;

//求得x,y使得 ax+by=gcd(a,b) 
ll exgcd(ll a,ll b,ll &x,ll &y){
	if(!b){
	x=1;y=0;return a;
	}else {
		ll ans = exgcd(b,a%b,x,y);
		ll temp=x;
		x=y;
		y=temp-a/b*y;
		return ans;
	}
}

//求逆元 ax = 1(mod m)
ll cal(ll a,ll m){
	ll x,y;
	ll gcd=exgcd(a,m,x,y);
	if(gcd==1)return (x%m+m)%m;
	else return -1; 
	
} 

int main(){
	SIS;
	int c;cin>>c;
	while(c--){
		ll a,b;
		cin>>a>>b;
		ll ans=cal(a,b);
	if(ans==-1)cout<<"Not Exist"<<endl;
	else if(ans==0)cout<<"1"<<endl;
	else cout<<ans<<endl;
	}
	return 0;
}

hdu1576

要求(A/B)%9973,但由于A很大,我们只给出n(n=A%9973)(我们给定的A必能被B整除,且gcd(B,9973) = 1)。


const int MAXN=2550;
const int MOD=9973;

//求得x,y使得 ax+by=gcd(a,b) 
ll exgcd(ll a,ll b,ll &x,ll &y){
	if(!b){
	x=1;y=0;return a;
	}else {
		ll ans = exgcd(b,a%b,x,y);
		ll temp=x;
		x=y;
		y=temp-a/b*y;
		return ans;
	}
}

//求逆元 ax = 1(mod m)
ll cal(ll a,ll m){
	ll x,y;
	ll gcd=exgcd(a,m,x,y);
	if(gcd==1)return (x%m+m)%m;
	else return -1; 
	
} 
int main(){
	SIS;
	int c;cin>>c;
	while(c--){
		ll a,b;
		cin>>a>>b;
		ll ans=cal(b,MOD);
		ans%=MOD;
		cout<<a*ans%MOD<<endl;
	}
	return 0;
}

另外还有两种求逆元的方式

//求1,2,...,N关于 M 的逆元(M为质数)
int inv[maxn];
inv[1] = 1;
for(int i = 2; i < 10000; i++)
    inv[i] = inv[mod % i] * (mod - mod / i) % mod;

//求阶乘的逆元
inv[maxn]=mod_pow(fac[maxn],mod-2);    // fac[] 是阶乘数组
for(ll i=maxn-1;i>=0;i--)
    inv[i]=(inv[i+1]*(i+1))%mod;
发布了20 篇原创文章 · 获赞 2 · 访问量 249

猜你喜欢

转载自blog.csdn.net/weixin_45535964/article/details/104994688