扩展欧几里得算法及其应用

扩展欧几里得算法不仅可以算出a,b的最大公约数 ,还可以给出不定方程ax+by = gcd(a,b)的一组解。这里a,b的正负不影响答案
对于任意的不定方程ax+by = d。若d%gcd(a,b) 不为0,则该不定方程无解。
证明
解不定方程:ax1 + by1 = gcd(a,b)
由欧几里得算法得 gcd(a,b) = gcd(b,a%b)
gcd(b,a%b) = bx2 + (a%b)y2
a%b = a - a/b
将a%b带入得
bx2 + (a - a/b)y2 = ay2 + b(x2 - a/b)
将 该式与原来的式子比较得:
ay2 + b(x2 - a/b) = ax1 + by1
x1 = y2
y1 = x2 - (a/b)y2

当b = 0时(递归的边界),x = 1,y = 0,回溯回利用上式求得x1,y1
当我们求出一个解时,有时需要求出通解或最小整数解。
ax + by = d
ax + b * y + n * a * (b/d) - n * (a / d ) b = d
(x+n*(b/d)) * a + (y-n*(a/d)) * b = d
所以通解为 x = x1 + n * (b/d),y = y1 - n * (a/d)
所以要求最小整数解就很简单了,要求x的最小整数解,只要模b/d即可。若等式右边是gcd的倍数时,求出结果后先乘上倍数,再取模(右边不管是什么,取模都成立),当b/d是负数时,求最小整数解直接取绝对值就好。

//扩展欧几里得,返回gcd(a,b),并且可以得到不定方程 ax + by = gcd(a,b)的一组解 
//通解为x = x1 + n * (b/d),y = y1 - n * (a/d)
//若等号右边为t,则通解为x= x1 * t /d + n * (b/d) 
//求最小整数解时直接取模(b/d)即可。
int ext_gcd(int a,int b,int &x,int &y)
{
	int d = a;
	if( !b )
	{
		x = 1;
		y = 0;
	}else
	{
		d = ext_gcd(b,a%b,y,x);
		y -= a / b * x;
	}
	return d;
} 

利用欧几里得算法计算逆元
x为b的逆元,则bx = 1(mod c) = 1 + cy
bx + cy = 1
若gcd(b,c) = 1,则不定方程有解,b的逆元存在,利用扩展欧几里得计算出x即可

void ext_gcd(int a,int b,int &x,int &y)
{
	if( !b )
	{
		x = 1;
		y = 0;
	}else
	{
		ext_gcd(b,a%b,y,x);
		y -= a / b * x;
	}
} 

int inv(int t,int p)  //求t关于p的逆元
{
	int x,y;
	ext_gcd(t,p,x,y);
	x = ( x % p + p ) % p;
	return x; 
}

求1~n中的数的逆元
利用逆元的线性递推关系就可以在O(n)的复杂度下求出1~n中的数关于p的逆元
推导:
设 p = k * i + r;(k = p / i , r = p % i)
k * i + r = 0(mod p)
两边同时乘以i^-1, r^-1
k * r^-1 + i^-1 = 0 (mod p)
i^-1 = -k * r^-1
将k与r带入得
i^-1 = -(p/i) * (p % i)^-1 mod p
由于p%i小于i,所以我们在计算i^ -1时,(p%i)^-1已经被算出来了
由于需要保证i^ -1>0,所以我们在右边加上p
i^-1 = p - (p/i) * (p % i)^-1 mod p

#include <cstdio>
using namespace std;
typedef long long ll;

ll inv[3000005];

int main()
{
	int n,p;
	scanf("%d%d",&n,&p);
	inv[1] = 1;
	printf("%lld\n",inv[1]);
	for (int i = 2; i <= n; i++)
	{
		inv[i] = p - (p/i) * inv[p%i] % p;
		printf("%lld\n",inv[i]);
	}
	return 0;
}

求1~n阶乘的逆元
对于阶乘的逆元也是有递推公式的,f[i+1] * inv[i+1] =1 = f[i] * (i+1*inv[i+1]) = f[i] * inv[i],所以inv[i] = inv[i+1] * (i+1)。

f[0]=1;
for(int i=2;i<=MAXN;i++)fac[i]=fac[i-1]*i%mod;
inv[MAXN]=q_pow(fac[MAXN],mod-2);
for(int i=MAXN-1;i>=0;i--)inv[i]=inv[i+1]*(i+1)%mod;
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值