数论学习1(欧几里德算法+唯一分解定理+埃氏筛+拓展欧几里德+同余与模算术)

目录

1. 唯一分解定理

2.欧几里德算法(求最大公约数)

3.求最小公倍数

4.埃氏筛

5.拓展欧几里德算法

(1)证明一下线性方程组的正数的最小值是多少,

(2)如何通过裴蜀定理退出拓展欧几里得算法(贝祖定理)

6.同余与模算术

(1)取模运算操作

加法取模运算

减法取模运算

乘法取模运算 

(2)特殊的取模操作

大整数取模

幂取模 

(3)同余式,乘法逆元,费马小定理


 今天也是小小的开始学习数论方面的知识了,首先数论的入门章节必然是欧几里德算法唯一分解定理

1. 唯一分解定理

定义:任何一个数都可以变成若干个质数相乘的形式

X=P1^a1*p2^a2*……*pk^ak;

也就是大家喜闻乐见的分解质因数

2.欧几里德算法(求最大公约数)

欧几里德算法,又称辗转相除法,是由递推式gcd(a,b)=gcd(b,a mod b)边界gcd(a,0)=a得来

int gcd(int a,int b)
{
	return b==0?a:gcd(b,a%b);
}

当然了,要是就最大公约数,《九章算术》中也提到了一种算法,名为更相减损术,也可以用于求最大公约数,每次都是大的数减去小的数,直到两数相同,就是最大公约数

int gcd(int a,int b)
{
     while(a != b)
     {
          if(a>b) a -= b;
          else b -=a;
      }
       return a;
}

3.求最小公倍数

我们由唯一分解定理可知

假设e为a的指数,f为b的指数

gcd(a,b)=p1^min(e1,f1) * p2^min(e2,f2) *…… *pk^min(ek,fk)

lcm(a,b)=p1^max(e1,f1) * p2^max(e2,f2) *…… *pk^max(ek,fk)

因此我们可以推出公式 gcd(a,b)*lcm(a,b)==a*b

那么我们的最小公倍数函数就为

int lcm(int a,int b)
{
	return a*b/gcd(a,b);
}

 不是哥们,这个你都信啊,有没有考虑过数据越界的问题,万一a*b数据越界怎么办?

所以上面那个是错的

实际上应该是,先除后乘,这样可以在一定程度上避免数据越界问题

int lcm(int a,int b)
{
	return a/gcd(a,b)*b;
}

4.埃氏筛

用来求素数表的方法,这个是在欧拉的基础上改良的方法

int vis[200005];//用于判断哪些数是素数,标记数组,0为素数,1为合数 

for(int i=2;i*i<=m;i++)
{
	if(vis[i]==0)
	for(int j=i*i;j<=n;j+=i)
	{
		vis[j]=1;
	}
} 

同时也有一个素数定理N(x)约等于·x / lnx

N(x)为不超过x的素数的个数

5.拓展欧几里德算法

再说拓展欧几里德算法之前,首先要去了解一个定理:裴蜀定理

设有线性方程组  ax+by=c;,那么gcd(a,b)|c  (a与b的最大公约数是c的因子),只有这样方程才有整数解

(1)证明一下线性方程组的正数的最小值是多少

 我们假设ax+by=d;   d为gcd(a,b)

s为ax+by的最小正值,设r=a mod s

证明:

a/s=q    余下r

r=a-qs

因为s=ax+by

r=a(1-qx)+b(-qy)

因为a,b,x,y都为整数

所以r也为整数,且为a,b的线性组合

又因为0<=r

所以r的值只能为0

因此s|a(s为a的因子),同理可证s|b(s也为b的这因子)

所以s为a,b的公约数,并且d>=s(因为d为最大公约数)

又因为d|a,d|b

所以d|(ax+by)

所以d|s且s>0

所以d<=s

所以d==s;

(2)如何通过裴蜀定理退出拓展欧几里得算法(贝祖定理)

 假设有方程a*x1+b*y1=gcd(a,b)且有b*x2+(a%b)*y2=gcd(b,a%b);

由欧几里得算法可知gcd(a,b)==gcd(b,a%b)

所以 a*x1+b*y1==b*x2+(a%b)*y2

对于取模来说有一个公式   a%b=a-a/b*b;

将上面这个公式代入等式并且分配之后得到结果:

a*x1+b*y1=a*y2+b*(x2-a/b*y2 )

所以可以说明

x1=y2

y1=x2-a/b*y2

即:

x2=y1+a/b+y2;

y2=x1;

写出代码:

int exgcd(int a,int b,int &x,int &y)
{
	if(b==0)
	{
		x=1,y=0;
		return a;
	}
	int d=exgcd(b,a%b,x,y);
	int t=x;//记录的x2 ,y就是y2 
	x=y;
	y=t-a/b*y;
	return d;
}

用途:

欧几里德算法是用来计算两个整数的最大公约数的一种方法。拓展欧几里德算法是在计算最大公约数的同时,还能找到一组整数解,使得这组解满足贝祖等式。

拓展欧几里德算法的应用有以下几个方面:

  1. 线性同余方程的解:利用拓展欧几里德算法可以求解形如ax ≡ b(mod m)的线性同余方程的整数解。这在密码学中有很多应用,比如RSA加密算法中,就用到了线性同余方程来实现加密和解密。

  2. 模逆元的计算:在计算机中,取模运算的逆元是非常重要的,可以使得一些运算更高效,比如在快速幂运算等中。拓展欧几里德算法可以用来计算模逆元。

  3. 应用于数论问题:拓展欧几里德算法还可以应用于解决一些数论问题,比如求解模线性方程组,计算最小公倍数等。

6.同余与模算术

(1)取模运算操作

加法取模运算

(a+b)%mod=(a%mod+b%mod)%mod;

减法取模运算

(a-b)%mod=(a%mod-b%mod+mod)%mod

乘法取模运算 

(a*b)%mod=(a%mod*b%mod)%mod 

那么就有人说了,这个是不是少了一个,是不是少了一个除法取模运算呢?答案是确实少了一个,但是那个涉及到乘法逆元了,我们要循序渐进 

(2)特殊的取模操作

大整数取模

比如说这么一道题:输入正整数n和m,然后输出n mod m的值,n<=10^100,m<=10^9

思路:我们可以把大整数写成自左向右的形式:比如说1234就可以写成((1*10+2)*10+3)*10+4

然后再每步都取模

#include
using namespace std;
#define int long long
char s[105];
int mod;
signed main()
{
	cin>>s;
	cin>>mod;
	ans=0;
	for(int i=0;i<=s.size();i++)
	{
		ans=(ans*10%mod+(s[i]-'0')%mod)%mod;
	}
	cout<

幂取模 

输入正整数a,n,m,输出a^n mod m的值,a,n,m<=10^9

思路:最简单的模拟很好写

int mod(int a,int n,int m)
{
	int ans=1;
	for(int i=0;i

但是我们会发现这种写法的时间复杂度( O(logN) )实在是太高了,在实际生活中你愿意一个一个的搞吗?

当然是不会的,我们要想办法减小上面这段代码的时间复杂度 ,我们可以用递归的方式,每次让数据的规模减小一半

int mod(int a,int n,int m)
{
	if(n==0)
	return 1;
	int x=mod(a,n/2,m);
	ans=(x%mod*x%mod)%mod;
	if(n%2==1)
	ans=ans*a%mod;
	return ans;
}

 这样的时间复杂度仅为O( logN )将会大大减少代码的时间复杂度

(3)同余式,乘法逆元,费马小定理

http://t.csdnimg.cn/PrZrs

之前的文章有写过,直接看我之前文章就行

你可能感兴趣的:(数学,数,算法,学习)