数论

数论


欧几里德算法


用于计算两个整数a,b的最大公约数。

基本算法:设a=qb+r,其中a,b,q,r都是整数,则gcd(a,b)=gcd(b,r),即gcd(a,b)=gcd(b,a%b)。
算法的实现(
递归算法)

  1. int gcd(int a,int b)    
  2. {    
  3.     if(b==0)  
  4.        return a;    
  5.     else   
  6.        return gcd(b,a%b);    
  7.  }    

扩展欧几里德算法:


基本算法:对于不完全为0的非负整数a,b,gcd(a,b)表示a,b的最大公约数,必然存在整数对 x,y,使得ax+by  gcd(a,b)

证明:

设 a>b

1)显然当 b=0,gcd(a,b)=a。此时 x=1,y=0;
2)ab!=0 时

设 a*x1+b*y1=gcd(a,b);   

   b*x2+(a mod b)*y2=gcd(b,a mod b);

根据欧几里德原理:gcd(a,b)=gcd(b,a mod b);

则:a*x1+b*y1=b*x2+(a mod b)*y2

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

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

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

根据恒等定理得:x1=y2; 

               y1=x2-(a/b)*y2;


算法实现(递归代码):

  1. int exgcd(int a,int b,int &x,int &y)  
  2. {  
  3.      int d,t;  
  4.      if(b==0)  
  5.      {  
  6.          x=1;  
  7.          y=0;  
  8.          return a;  
  9.      }  
  10.      r=exgcd(b,a%b,x,y);  
  11.        
  12.      t=x;  
  13.      x=y;  
  14.      y=t-a/b*y;  
  15.   
  16.      return d;  
  17. }  
#include<stdio.h>  
int exgcd(int a, int b, int &x, int &y)   
{  
    int d,tmp;   
    if (b==0)   
    {  
        x = 1;  
        y = 0;   
        return a;    
    }   
    d = exgcd(b,a%b,x,y);   
    tmp = x;  
    x = y;   
    y = tmp - a/b * y;  
    return d;   
}   
int main()  
{  
    int a,b,x,y,k;  
    scanf("%d %d",&a,&b);  
    k=exgcd(a,b,x,y);  
    printf("%d %d %d\n",k,x,y);  
    return 0;  
}  



求解不定方程(扩展欧几里德算法)


对于不定整数方程a*x+b*y=c,若c mod Gcd(a,b)=0,则该方程存在整数解,否则不存在整数解。


找到a*x+b*y = Gcd(a,b)的一组解(x0,y0)后
a*x+b*y = Gcd(a,b)的其他整数解满足:
x = x0 + b/Gcd(a,b) * t 
y = y0 - a/Gcd(a,b) * t   (其中t为任意整数)

至于a*x+b*y=c的整数解,只需将a*x+b*y=Gcd(a,b)的每个解乘上 c/Gcd(a,b) 即可。
找到a*x+b*y = Gcd(a,b)的一组解(x0,y0)后,
得到a*x+b*y=c的一组解(x1,y1)为:
x1 = x0*(c/Gcd(a,b))
y1 = y0*(c/Gcd(a,b))

找到a*x+b*y=c的一组解(x1,y1)后,
a*x+b*y=c的其他整数解满足:
x = x1 + b/Gcd(a,b) * k
y = y1 - a/Gcd(a,b) * k   (其中k为任意整数)
x 、y就是a*x+b*y=c的所有整数解。
 
用扩展欧几里得算法解不定方程ax+by=c;
代码如下:
复制代码
1 bool linear_equation(int a,int b,int &x,int &y)
2 {
3     int d=exgcd(a,b,x,y);  // 方程a*x+b*y=c
4     if(c%d)
5         return false;
6     int k=c/d;
7     x*=k; y*=k;    //求得的只是其中一组解
8     return true;
9 }
复制代码



同余

定义:用给定的正整数m分别除整数a、b,如果所得的余数相等,则称a、b对模m同余,记作a≡b(mod m)。

定理1:整数a,b对模m同余的充要条件是 a-b能被m整除(即m|a-b)。
推论:a≡b(mod m)的充要条件是a=mt+b(t为整数)。

定理2:同余关系具有反身性、对称性与传递性,即
1)a≡a (mod m);
2)若a≡b (mod m), 则b≡a (mod m);
3)若a≡b (mod m), b≡c (mod m),则a≡c (mod m).

定理3 若a≡b(mod m), c≡d (mod m),则
1)a+c≡b+d (mod m);
2)a-c≡b-d (mod m);
3)ac≡bd (mod m).
推论:若a≡b(mod m),n为自然数,则an≡bn (mod m)。

定理4:若ca≡cb(mod m), (c,m)=d (c,d最大公约数为d),且a,b为整数,则a≡b(mod m/d).
推论:若ca=cb(mod m), (c,m)=1 (c,d最大公约数为1,即互质),且a,b为整数,则a≡b(mod m).

定理5:若a≡b (mod m),a≡b (mod n),则a≡b(mod [m,n]).
推论若a≡b(mod mi), i=1,2,…,n,则a≡b (mod [m1,m2,..,mn]).


求解模线性方程(扩展欧几里德算法):

求解同余方程 ax≡b (mod n) 相当于求解方程 ax + ny = b, (x, y为整数)

当且仅当 gcd(a,n)|b时,同余方程ax≡b(mod n)对于未知数x有解。且方程有解时,方程有gcd(a,n)个解。

证明:

d=gcd(a,n),假如整数x和y,满足ax+ny=d( 由扩展欧几里德得出)。

如果d|b时(即:b%d==0),则方程a*x0+ n*y0= d,方程两边乘以 b/d,得到:a*x0*b/d+ n*y0*b/d= b。

所以 x=x0*b/d,y=y0*b/d 为 ax+ ny= b 的一个解。(x0,y0为方程ax+ny=d=gcd(a,n)的一组解
所以 x=x0*b/d 为 ax=b(mod n) 的解。

同余方程ax≡b(mod n)的一个解(x0`)为:x0`=x0*(b/d)mod n。


例如:5x=4(mod3),解得x = 2,5,8,11,14.......由此可以发现一个规律,就是解的间隔是3.
我们设解之间的间隔为dx.
那么有:
a*x = b(mod n);
a*(x+dx) = b(mod n);
两式相减,得到:a*dx(mod n)= 0;
也就是说a*dx就是a的倍数,同时也是n的倍数,即a*dx是a 和 n的公倍数.为了求出dx,我们应该求出a 和 n的最小公倍数,此时对应的dx是最小的.
设a和n的最大公约数为d,那么a和n的最小公倍数为(a*n)/d.
即a*dx = a*n/d;
所以dx = n/d.
因此解之间的间隔就求出来了.


所以:方程的d个解分别为:xi=(x0`+i*(n/d))mod n  {i=0,1,2 ... d-1}。
复制代码
 1 bool modular_linear_equation(int a,int b,int n)
 2 {
 3     int x,y,x1,i;
 4     int d=exgcd(a,n,x,y);
 5     if(b%d)
 6         return false;
 7     x1=x*(b/d)%n;   //特解
 8     for(i=1;i<d;i++)
 9         printf("%d\n",(x1+i*(n/d))%n);
10     return true;
11 }
复制代码

求模的逆元(欧几里德算法):


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

如果 b== 1,同余方程就是 ax=1 (mod n ),gcd(a,n)= 1。这时称求出的 x 为 a 的对模 n 乘法的逆元。

同余方程 ax= 1(mod n ), gcd(a,n)= 1 的求解就是求解方程ax+ ny= 1(x, y 为整数).


中国剩余定理(求解同与方程组)


问题:一个数被3除余1,被4除余2,被5除余4,这个数最小是几?

解法:x%3=1,  x%4=2,  x%5=4;

           也就是求同余式组x≡1(mod3),x≡2(mod4),x≡4(mod5)的正整数解.

           题中3、4、5三个数两两互质。则〔4,5〕=20;〔3,5〕=15;〔3,4〕=12;〔3,4,5〕=60。

           使20被3除余1(1)(即(20*x1)%3=1),x1=2。用20×2=40;

           使15被4除余1(2)(即(15*x2)%4=1),x2=3。用15×3=45;

           使12被5除余1(4)(即(12*x3)%5=1),x3=3。用12×3=36;

          //让余数为1,是为了要求余数4的话,只要乘以4就可以;要求余数为2的话,只要乘以2就可以……

           然后,40×1+45×2+36×4=274,因为,274>60,所以,274-60×4=34,就是所求的数。

问题:
给定两两互质的正整数n1,n2,...,nk,要求找到最小的正整数a,满足a≡ai (mod ni)   //ai 表示余数
算法步骤:
令n=n1n2...nk,mi=n/ni       // n=60, m1=20, m2=15, m3=15
显然gcd(mi,ni)=1,解模线性方程,计算出xi满足mi*xi≡1 (mod ni)      //(20*x1)%3=1  -->  x1=2
a≡a1*x1*m1+a2*x2*m2+...+ak*xk*mk (mod n)        // a1*x1*m1  (1*2*20)


算法实现:


#include <cstdio>    
#include <cstring>    
#include <iostream>    
using namespace std;    
int gcd(int a,int b,int &x,int &y)    
{  
      
    int d,temp;  
    if(b==0)   // 不定方程 a*x+b*y=gcd(a,b)=d;(x,y)为其一组整数解  
    {  
        x=1;  
        y=0;  
        return a;  
    }    
    d = gcd(b,a%b,x,y);   
    temp = x;  
    x = y;   
    y = temp - a/b * y;  
    return d;   
}    
  
int main()    
{    
    int m,m1,r1,m2,r2,flag=0;  
    int a[11],b[11],T;    
    cin>>T;    
    while(T--)    
    {       
        int i,j;  
        int x,y,d,c,t;  
          
        cin>>m;    
        for(i=0;i<m;i++)    
            cin>>a[i];    
        for(i=0;i<m;i++)    
            cin>>b[i];   
          
        // x%m1=r1,x%m2=r2 ...  
        // x=m1*k1+r1,x=m2*k2+r2 ... (k1,k2 ... 为任意整数)  
        // m1*k1-m2*k2=r2-r1 ...  
          
        flag=0;    
        m1=a[0];r1=b[0];    
        for(i=1;i<m;i++)    
        {    
            m2=a[i];r2=b[i];    
            if(flag)  
                continue;    
            d=gcd(m1,m2,x,y);   // 方程 x*m1+y*m2=d=gcd(m1,m2);    
            c=r2-r1;    
            if(c%d)          //对于方程m1*x+m2*y=c=r2-r1,如果c不是d的倍数就无整数解    
            {    
                flag=1;    
                continue;    
            }  
            //对于方程m1*x+m2*y=c=r2-r1,若(x0,y0)是一组整数解,那么(x0+k*(m2/d),y0-k*(m1/d))也是一组整数解(k为任意整数)    
            //其中x0=x*(c/d),y0=y*(c/d); (x,y为方程m1*x+m2*y=d=gcd(a,b)的一组整数解)  
            t=m2/d;    
            x=(c/d*x+t)%t;       
              
            r1=m1*x+r1;    
            m1=m1*m2/d;    
        }    
        if(flag)  
            cout<<0<<endl;    
        else                
            cout<<r1<<endl;      
    }    
    return 0;    
}    


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值