10.1数论初步

来源:互联网 发布:热血传奇手游源码 编辑:程序博客网 时间:2024/05/22 04:47

10.1.1欧几里得算法和唯一分解定理

除法表达式

分析:

表达式的值一定可以写成A/B的形式:A是其中一些Xi的乘积,而B是其他数的乘积,而B是其他数的乘积。不难发现,X2必须放在分母位置,那其他数呢?

其他数均可以放在分子位置

接下来的问题就变成了:判断E是否为整数

第一种方法是利用前面介绍的高精度运算:k次乘法加一次除法,正确但是麻烦

第2种方法是利用唯一分解定理,把X2写成若干素数相乘的形式:

第3种方法是直接约分:每次约掉Xi和X2的最大公约数gcd(Xi,X2),则当且仅当约分结束后X2=1时E为整数,程序如下

int judge(int* X){    X[2]/=gcd(X[2],X[1]);    for(int i=3;i<=k;i++)        X[2]/=gcd(X[i],X[2]);    return X[2]==1;}
整个算法的时间效率取决于这里的gcd算法。

辗转相处法的关键在于如下恒等式: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);}

利用gcd还可以求出两个整数a,b的最小公倍数lcm(a,b)

不难验证gcd(a,b)*lcm(a,b)=a*b,不过即使有了公式也不要大意,如果把lcm写成a*b/gcd(a,b),可能会出错,因为a*b会溢出,正确的写法是先除后乘,即a/gcd(a,b)*b

10.1.2Eratosthenes筛法

无平方因子的数。给出正整数n,m,区间[n,m]内的“无平方因子”的数有多少个?

分析:

对于这样的限制,直接枚举判断会超时:需要判断10***0个整数,所以需要用Eratosthenes筛法构造1~n的素数表

筛法的思想特别简单:对于不超过n的每个非负整数p,删除2p,3p,,,当处理完所有数之后,还没被删的就是素数,用VIS[i]表示i已经被删除

memset(vis,0,sizeof vis);for(int i=2;i<=n;i++)    for(j=i*2;j<=n;j+=i)        vis[j]=1;

10.1.3扩展欧几里得算法

直线上的点。求直线ax+by+c=0上有多少个整点,满足x [x1,x2],y [y1,y2]

分析:

在解决这个问题之前,首先学习欧几里得算法——找出一对整数(x,y),使得ax+by=gcd(a,b).注意,这里x和y不一定是正数,也可能是负数或者0.例如,gcd(6.15)=3,6*3-15*1=3,其中x=3,y=-1.这个方程还有其他解,如x=-2,y=1

下面是扩展欧几里得算法的程序

void gcd(int a,int b,int& d,int& x,int& y){    if(!b)    {        d=a;x=1;y=0;    }    else    {        gcd(b,a%b,d,y,x);        y-=x*(a/b);    }}
用数学归纳法并不难证明算法的正确性,注意在递归调用时,x和y的顺序变了,而边界也是不难得出的:gcd(a,0)=1*a-0*0=a.这样,唯一需要记忆的是y-=x*(a/b),不懂也不要紧。

上面求出了ax+by=gcd(a,b)的一组解(x1,y1),?其他解?任取另外一组解(x2,y2),则ax1+by1=ax2+by2(他们都等于gcd(a,b)),变形得a(x1-x2)=b(y2-y1),近一些列的变形得出

他的任意数解都可以写成(x0+kB,y0-kA),A=a/gcd(a,b),B=b/gcd(a,b),k取任意整数

。。。。。。

10.1.4同与与模算术

可得下面公式

(a+b)mod n=((a mod n)+(b mod n))mod n

(a-b)mod n=((amodn)-(bmodn)+n)mod n

注意在减法中,由于a mod n可能小于b mod n,需要在结尾上+n,以及乘法过程中可能会溢出

int mul_mod(int a,int b,int n){    a%=n; b%=n;    return (int)((long long)a*b%n);}
分析:

首先,把大数写成自左向右的形式:1234=((1*10+2)*10+3)*10+4

scanf("%s%d",n,&m);int len=strlen(n);int ans=0;for(int i=0;i<len;i++)    ans=(int)(((long long)ans*10+n[i]-'0')%m);printf("%d\n",ans);
这个函数的时间复杂度为n,当n很大时速度不理想

下利用分治法

int pow_mod(int a,int n,int m){    if(n==0)        return 1;    int x=pow_mod(a,n/2,m);    long long ans=(long long)x*x%m;    if(n%2==1)        ans=ans*a%m;    return (int)ans;}
//不是很懂





0 0
原创粉丝点击