HDU - 1576 乘法逆元(扩展欧几里得算法) 难度:算法入门 复杂度:有点复杂 (待完善)...

77110c97ece9260d4b04bbd3e7969418763.jpg

先简介下扩展欧几里得算法:

据说可以证明方程ax+by=gcd(a,b)必然有解,而且不止一组解(gcd指最大公约数)

朴素的欧几里得算法就是辗转相除法,用来求gcd的

因为ff67cf717f8688852acd41fe14a284f74ba.jpg

最后会有一方等于0,就能求出gcd(a,b),这就是辗转相除法

 

扩展欧几里得算法可以解出方程ax+by=gcd(a,b)的一组解,假设a>b>=0
以下是一段简单的推导:

c5be3d3f6e8f1ea363892fbf2b77b9ba001.jpg

因此,只要知道x2,y2就能知道x1,y1,而x2,y2也能通过x3,y3得知,这样往下递推到b=0为止

回到题目中,设X=A/B,

d3f23bb0c379144e530445bc61a3c690bfc.jpg

x*B+9973*y=gcd(B,9973)=1,用扩展欧几里得算法可以算出这个方程的一组解,即x和y可知
方程两边乘以n得x*n*B+y*n*9973 = n = XB+A/9973*9973
对比式子两边可知x*n=X
那么知道了x就知道X了,X就是A/B
X%9973(即x*n%9973)就是题目要的答案

但问题又来了,扩展欧几里得算法算出的x是负数怎么办?
负数取模再加一份模得到正数,然后输出即可,即x*n%9973+9973
(由于本人暂时也不太明白为何负数取模要想得到正数结果在这题当中可以这样转化,加上时间紧迫,只能回头再做补充了,至少代码能A)

390076b3f668c475587560360e9f5ba2018.jpg

#include<iostream>
using namespace std;
int exGcd(int a, int b, long long &x, long long &y)
{
	if (b == 0)
	{
		x = 1;
		y = 0;
		return a;
	}
	int r = exGcd(b, a%b, x, y);
	int t = x;
	x = y;
	y = t - a / b * y;
	return r;
}
int main()
{
	int T;
	cin >> T;
	long long n, B;
	long long x, y;
	for (T; T > 0; T--)
	{
		cin >> n >> B;
		exGcd(B, 9973, x, y);
		cout << x*n % 9973 + 9973 << endl;
	}
	return 0;
}

 

转载于:https://my.oschina.net/u/4035395/blog/3011482

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值