数论基础

求最大公约数

求最大公约数,采用的是欧几里得算法,其描述如下:

gcd(a,b) = gcd(b,a mod b) (a>b 且a mod b 不为0)

下面给出证明过程:

1. 将a表示为a = kb + r,其中r = a mod b。

2. 设d | a且d | b(即d为a,b的一个公约数)。则由d | a,d | b => d | (a - kb) => d | r

3. 由d | b,d | r可知d也是(b, a mod b)的公约数

4. 由于d的选取的任意性,(a, b)和(b, a mod b)的公约数一致,最大公约数也相同,得证。

C语言代码如下(递归):

int gcd(int x, int y)
{
	return y == 0 ? x : gcd(y, x%y);
}


求模乘的逆

ab ≡ 1 mod n,已知a和n,求b。

解法需采用上一节中的欧几里得算法,将每一步的商(a / b)记录下来并压栈。然后再出栈经过计算获得逆元的值。

下面是完整的C++代码,使用递归求解。

#include <iostream>
#include <stack>
using namespace std;

stack<int> num;  //声明一个存放辗转相除每一步除数的向量
void gcd(int x, int y);
int getb(int x, int y);

int main()
{
	int a = 37, b, n = 1700;  //ab=1 mod n
	gcd(n, a);  //辗转相除
	b = getb(0, 1);  //获取模逆
	printf("%d\n", b > 0 ? b : n + b);  //结果可能是负数,将其转化为正数后输出
}

void gcd(int x, int y)  //辗转相除(递归)
{
	if (y == 1)
		return ;
	num.push(x / y);  //将除数压栈
	gcd(y, x % y);  //递归
}

int getb(int x, int y)  //获取模逆(递归)
{
	if (num.size())
	{
		int top = num.top();  //获取栈顶元素
		num.pop();  //出栈
		return getb(y, x - y * top);  //递归
	}
	return y;
}


扩展欧几里得算法

x * a + y * b = c, 已知a, b, c,求x, y

扩展欧几里得算法常用于解模线性方程及方程组

扩展欧几里得定理,描述如下:

已知a,b,满足p * a + q * b = gcd(a, b)的(p, q)一定存在

证明过程略,有兴趣可以参考相关数论书籍。

扩展欧几里得算法的C++语言描述如下(递归):

#include <iostream>
using namespace std;

int a = 21, b = 35;
int x, y;
void getres(int r1, int r2, int x1, int x2, int y1, int y2);

int main()
{
	int x1 = 1, y1 = 0, x2 = 0, y2 = 1;
	getres(a, b, x1, x2, y1, y2);
	printf("%d %d", x, y);
}

void getres(int r1, int r2, int x1, int x2, int y1, int y2)
{
	int q, m, n;
	if(r2 = a * x2 + b * y2)
	{
		q = r1 / r2;
		m = x1 - q * x2;
		n = y1 - q * y2;
		x = x2, y = y2;
		getres(r2, r2, x2, m, y2, n);  //递归
	}
}


求欧拉函数

欧拉函数值,即小于n且与n互素的数的个数,记作p(n)。

性质:

1. n为素数时,p(n) = n -1

2. p(p * q) = p(p) * p(q)  (p, q互素)

用上述性质即可完成欧拉函数的求解。

C++代码(输入n,输出p(n)):

int p(int n)
{
	int m = (int)sqrt(n);
	int ans = n;
	for (int i = 2; i <= m; i++)
	if (n % i == 0)  //依次处理素因子
	{
		ans = ans / i * (i - 1);
		while (n % i == 0) 
			n /= i;   //将素因子i除干净
	}
	if (n > 1)
		ans = ans / n * (n - 1);
	return ans;
}






  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值