数论的基础入门(初读数论概论有感)(acm知识储备)

在寒假自己对自己的硬核知识进行了充电,这本书是学长极力推荐的,是专门给数学系的学生进行对数论进行全面认识和理解的入门书籍,虽然自己是计算机的,但是并不影响去阅读它,读的过程中就发现了,书中不少数学系的知识映入眼帘,我确实有点慌,有选择的进行了阅读。读的比较仓促,但是读完确实是有如神助,补齐了自己之前在学习acm数论的不少的坑,让自己对一些知识有了更深的认识。比如拓展欧几里得和欧拉函数。

-一。毕达哥拉斯定理(勾股定理)

a^2+b^2=c^2;(a,b的奇偶性是相反的,且c总是奇数)

有一个神奇的规律就是存在两个数字s,t,使得a=s*t, b=(s^2-t^2)/2, c=(s^2+t^2)/2;

这个比较有实用价值,是对从小就开始学习的勾股定理有了实际性的鼓励总结。

二。费马大定理

a^n+b^n=c^n。(当n>=3,方程式无解)

很显然当n==0时这个等式不成立的,所以范围就从整个整数域缩到了{0,1,2}, 又缩小到{1,2}。看是很鸡肋的定理,但是这个就是作为常识的存在在acm题目中。

三。欧几里得算法和拓展欧几里得算法

gcd(a,b)为a,b的最大公因子,LCM(a,b)为a,b的最小公倍数。

且二者存在关系LCM(a,b)*gcd(a,b)=a*b;

欧几里得算法实质上就是由直到余数为零的一系列带余除法组成的。

注意如何在每一步用A除以B得到商Q和余数R,A=B*Q+R,然后在下一步用数B与R代替原来的A与B,继续此过程直到得到余数R==0为止。

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

我经常更加形象化的理解,就是给我们一个长方形的纸条,问这个纸条中构成它的最大的基础正方形的边长是多少。(即由有限个基础正方形构成所提供的长方形,求解它的最大边长)。

首先咱们将这个长方形进行撕开,撕下最大的一个正方形,那么留下一个新的长方形,之后再次进行这个操作,直到再次撕完之后剩下的是个正方形为止。那么这个正方形就是该长方形的最大基础正方形,它的边长就是提供长方形的长宽的最大公因子。

ax+by的最小正整数值为gcd(a,b).

所以咱们去求解ax+by=gcd(a,b)

下边以22x+60y=gcd(22,60)为例,a=60,b=22;

60=2*22+16         |    16=a-2b

22=1*16+6           |    6=b-(a-2b)=3b-a

16=2*6+4             |    4=a-2b-2(3b-a)=3a-8b

4=2*2+0               |    2=3b-a-3a+8b=-4a+11b

over                      |   始终把握,最新余数=a的倍数*a+b的倍数*b

 

所以22*11-60*4=gcd(22,60)=2;

过程可以概述为左边等式是欧几里得算法,右边的等式是计算ax+by=gcd(a,b)的解

int exgcd(int a,int b,int &x,int &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;
}

解释:显然当b==0时,gcd(a,b)=a;此时x=1,y=0;

                  当ab<>0时,设ax1+by1=gcd(a,b)

                                          bx2+(a mod b)y2=gcd(b,a mod b);

                  又因为gcd(a,b)=gcd(b,a mod b)

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

                     等式左右恒成立,x1=y2,y1=x2-(a/b)*y2;

 

注意使用exgcd求解的x,y是一组解,然后其通解为(x+kb,y-ka)

a*(x+kb)+b*(y-ka)=ax+kab+by-kab=ax+by;

拓展欧几里得的实际应用:

①求模的逆元

同余方程ax≡b(mod n)   若gcd(a,n)=1,则方程只有唯一的解。

在这种情况下,若b==1, 同余方程为ax≡1(mod n), gcd(a,n)=1,这时称求出的x为a的对模n的乘法逆元,实际就是求解方程ax+ny=1的x解。

②线性同余方程

ax≡b(mod n)

当b%(gcd(a,n))==0,则有解,且恰好有gcd(a,n)个解。 x=x0+k*n/g(k=0,1,.....g-1)

可转换为ax+ny=b.

③求解不定方程 

ax+by=c

首先要保证c%(gcd(a,b))==0,则有解

设g=gcd(a,b)

a'=a/g  b'=b/g  cc'=c/g;

则a'x'+b'y'=1的解  可exgcd求解

a'c'x'+b'c'y'=c'可求

a'gc'x'+b'gc'y'=c'g

即ac'x'+bc'y'=c

所以x0=c'x'  y0=c'y';

四。费马小定理

设p是素数,a是任意整数且a≠0(mod p) 

则 a^(p-1)≡1(mod p)

用途可简化幂的取模运算

2^35(mod 7) =2^(6*5+5) (mod 7)= (2^6 (mod 7) )^5 * 2^5(mod 7)=1^5 * 2^5 (mod 7) =32 (mod 7) =4

是不是觉得这样简直好用到哭泣啊,但是如果p不是素数的时候应该怎么办呢,这个时候就提出了欧拉函数这个神奇的东西

五。欧拉函数

1.欧拉函数

Φ(m)=  #{a: 1<=a<=m, gcd(a,m)=1 }.   #是求解这个集合中的元素的数目的。

所以Φ(m)就是表示从1到m之间与m互素的整数的数目。

明显可知 ,若m是素数,Φ(m)=m-1。

欧拉函数的特殊:①如果p是素数,且k>=1,则Φ(p^k)=p^k-p^(k-1);

                            ②如果gcd(m,n)=1,则Φ(mn)=Φ(m)*Φ(n);

                            ③设p1,p2,p3......pr 都是整除m的不同素数,则Φ(m)=m*(1-1/p1)*(1-1/p2)....*(1-1/pr);

                            ④如果p是素数,对于任意整数n,Φ(n*p)的值的求解

                                ⅰ  若n不可以整除p,Φ(n*p)=Φ(n)*Φ(p);

                                 ⅱ 若n可以整除p,Φ(n*p)=Φ(n)*p;

2.欧拉公式

如果gcd(a,m)=1,则a^Φ(m)≡1(mod m)

int Eluer(int n)//求解某个数的欧拉函数
{
	int ret=n;
	for(int i=2;i<=sqrt(n);i++)
	{
		if(n%i==0)
		{ 
			ret=ret/i*(i-1);
			while(n%i==0)
				n/=i;
		}	 
	}
	if(n>1)
		ret=ret/n*(n-1);
	return ret; 
}
//求解1-n这个区间的所有数的欧拉函数值
const int maxn=1e5+100;
int prime[maxn];
int phi[maxn];
bool flag[maxn];
int num=0;

void eluer(int n)
{
	phi[1]=1;
	for(int i=2;i<=n;i++)
	{
		if(flag[i]==0)
		{
			prime[++num]=i;
			phi[i]=i-1;
		}
		for(int j=1;j<=num&&prime[j]*i<=n;j++)
		{
			flag[prime[j]*i]=1;
			if(i%prime[j]==0)
			{
				phi[i*prime[j]]=phi[i]*prime[j];
				break;
			}
			else
			{
				phi[i*prime[j]]=phi[i]*phi[prime[j]];
			}
		}
	}
}  

六。中国剩余定理(CRT)

设正整数m1,m2,.....mk两两互素,则存在同余方程组

   x≡a1(mod m1)

   x≡a2(mod m2)

   x≡a3(mod m3)

   .............

   x≡ak(mod mk)

存在整数解x

咱们研究的就是怎样求出来在这个x。

明显可知,在模M=m1*m2*....*mk的情况下,x是唯一存在的,

x=(a1*M1*M1^-1 +a2*M2*M2^-1 +.....+ak*Mk*Mk^-1)(mod M)

其中Mi =M/mi ,而Mi^-1 为Mi 在M的逆元。


int exgcd(int a,int b,int &x,int &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 CRT(int a[],int m[],int n)
{
	int M=1;
	int ans=0;
	for(int i=1;i<=n;i++)
		M*=m[i];
	for(int i=1;i<=n;i++)
	{
		int x,y;
		int Mi=M/m[i];
		exgcd(Mi,m[i],x,y);
		ans=(ans+a[i]*Mi*x)%M;
	}
	if(ans<0)
		ans+=M;
	return ans;
}
int main()
{
	int a[]={0,2,3,2};
	int m[]={0,3,5,7};
	printf("%d\n",CRT(a,m,3));
}

七。斐波那契兔子问题与线性递归序列

递推公式

F1=1,F2=1,Fn=Fn-1+Fn-2,n>=3;

比内公式

Fn=1/√5  { ((1+√5 )/2)^n-((1-√5 )/2)^n }

 

整理的思路有些零散,只是初次阅读的一些收获,记录一下(= =)!

你可能感兴趣的:(个人感悟)