线性同余方程组

写在前面:

  记录了个人的学习过程,同时方便复习

  笔者渣渣,网上的证明看不懂,只能自己证

  注意不要把中国剩余定理和解线性同余方程组混为一谈

  中国剩余定理仅仅是一个很巧妙的算法

  在学习如何解线性同余方程组之前,根本没必要学习中国剩余定理

 

  本篇全原创,转载请留言

 

目录

 

by otakuap

 

  • 线性同余方程组是否有解

  同余方程组的解什么时候存在呢?

  先假设要解这么一个同余方程组:

    x ≡ a1 (mod b1)

    x ≡ a2 (mod b2)

    ……

    x ≡ an (mod bn)

    我们假设其中的每一个同余方程都成立!

  我在[◹]拓展欧几里得算法的应用④中提到了同余方程的一个有趣的性质:放缩性

  利用放缩,我们来把所有的模数变成一样的!

    定义B=Πni=1 bi

    根据放缩,则上面那个同余方程组可以转化为:

    x*B/b1 ≡ a1*B/b1 (mod B)

    x*B/b2 ≡ a2*B/b2 (mod B)

    ……

    x*B/bn ≡ an*B/bn (mod B)

  在同余方程组中有这么一个显然的性质:

    在同一模数的意义下,同一个数的对应值不能有多个!(在函数中可以多对一,不能一对多)

  一旦出现

    x*B/bi ≡ c (mod B)

    x*B/bi ≡ d (mod B)

    cd为非负整数,且c!=d

  那么一定无解

  这就是同余方程组有解无解的本质了

  在这里可以得到上面的线性同余方程组的成立条件:

① 每一组同余方程都有解

(详见[◹]拓展欧几里得算法应用④)

② 每一个x*B/bi都唯一对应一个ai*B/bi

  只要以上条件有一个不满足,那么这组同余方程一定无解!

  在中国剩余定理解线性同余方程组中,模数两两互质

  保证了对应的唯一性

  这就是为什么中国国剩余定理来解线性同余方程组,要么不能解,要么一定有解

 

  • 解的周期性

  首先假设有多个周期函数f(x),他们的周期分别为Ti

  这多个周期函数方程组成的方程组的解的最小正周期为T

  则显然,TTi的最小公倍数

 

  同理

  先假设要解这么一个同余方程组:

    x ≡ a1 (mod b1)

    x ≡ a2 (mod b2)

    ……

    x ≡ an (mod bn)

    我们假设其中的每一个同余方程都成立!

  利用放缩,我们来把所有的模数变成一样的!

    定义B=LCM(bi)

注意此处是最小公倍数而不单单是积

    根据放缩,则上面那个同余方程组可以转化为:

    x*B/b1 ≡ a1*B/b1 (mod B)

    x*B/b2 ≡ a2*B/b2 (mod B)

    ……

    x*B/bn ≡ an*B/bn (mod B)

  解这么一组线性同余方程组,如果有解,那么它的最小非负整数解一定是[0,B-1]这个区间中的某个整数!

 

  • 失败的尝试

某只马血的教训

  先来看一个同余方程组中有趣的性质:

性质:

A1 ≡ B1 (mod C)

A2 ≡ B2 (mod C)

如果这两个同余式都成立,那么一定有:

A1+A2 ≡ (B1+B2)%C (mod C)

暂且叫这条性质为可加性

 

证明:

  根据%运算的分配律

    (a+b)%c == ((a%c)+(b%c))%C

  则有

    若a ≡ a%c (mod c)

    b ≡ b%c (mod c)

    则a+b ≡ ((a%c)+(b%c))%c (mod c)

  这个尝试的思路,大概是先把模数都弄成一样的,然后转化出该线性同余方程组的最终同余方程

  利用[◹]拓展欧几里得算法的应用④,判定这个最终方程有没有解,解出来是多少

    如果有解,不能说明该线性同余方程组有解

    如果无解,不能说明该线性同余方程组无解

  为什么呢?

  因为可加性的逆命题是假命题

  举个例子:

    x ≡ 2 (mod 3)

    x ≡ 5 (mod 6)

    x ≡ 2 (mod 7)

  根据放缩,有

    14x ≡ 28 (mod 42)

    7x ≡ 35 (mod 42)

    6x ≡ 12 (mod 42)

  根据可加性,有

    27x ≡ 33 (mod 42)

  解得一个x==9

  反带回去:

    14*9 ≡ 0 (mod 42)

    7*9 ≡ 21 (mod 42)

    6*9 ≡ 12 (mod 42)

  根本不成立

 

  同余方程组中还有一个趣的性质:

性质:

A1 ≡ B1 (mod C)

A2 ≡ B2 (mod C)

如果这两个同余式都成立,那么一定有:

A1*A2 ≡ (B1*B2)%C (mod C)

暂且叫这条性质为可乘性

 

证明:

  根据%运算的分配律

    (a*b)%c == ((a%c)*(b%c))%C

  则有

    若a ≡ a%c (mod c)

    b ≡ b%c (mod c)

    则a*b ≡ ((a%c)*(b%c))%c (mod c)

  和可加性一样,利用可乘性求解x的尝试也是失败的

  因为可乘性的逆命题是假命题

  举个例子:

    x ≡ 5 (mod 6)

    x ≡ 2 (mod 7)

  根据放缩,有

    7x ≡ 35 (mod 42)

    6x ≡ 12 (mod 42)

  根据可乘性,有

    42x ≡ 0 (mod 42)

  显然,x为任意整数

  更别说什么反带回去了

 

  虽然这两个尝试都失败了,但是它们还是很有价值的

 

  • 解线性同余方程组

  首先,在[◹]拓展欧几里得算法中提到的放缩的逆命题是真命题

  其次,我们已经知道了什么情况下,待解的线性同余方程组有解

  我们可以采用拆分,合并的解法来解决问题:

  先假设要解这么一个同余方程组:

    x ≡ a1 (mod b1)

    x ≡ a2 (mod b2)

    ……

    x ≡ an (mod bn)

    其中可能有些同余方程根本就没有解,详见[◹]拓展欧几里得算法

  定义B=LCM(bi)

  根据放缩,则上面那个同余方程组可以转化为:

    x*B/b1 ≡ a1*B/b1 (mod B)

    x*B/b2 ≡ a2*B/b2 (mod B)

    ……

    x*B/bn ≡ an*B/bn (mod B)

  根据有无解的条件②,先判断有没有一对多的情况

    如果有,那么肯定无解

    如果没有,那么可能有解,继续

  然后根据有无解的条件①,一个个判断有无 无解的同余方程 并求出xi,xi都是最小非负整数解

    如果存在无解的同余方程,那么一定无解

    如果不存在无解的同余方程,那么一定有解

 

待完成

 

  1 #include<bits/stdc++.h>
  2 
  3 using namespace std;
  4 
  5 int const MAXN=10010;
  6 int x,y,tmpb,tmpa,tmp,times;
  7 int k;//k组同余方程
  8 int a[MAXN];//每个同余方程的余数
  9 int b[MAXN];//每个同余方程的模数
 10 int bi[MAXN],ai[MAXN];
 11 int B=1;
 12 
 13 void C_swap(int &a,int &b){int c=a;a=b;b=c;return;}
 14 
 15 int exgcd(int a,int b)
 16 {
 17     if(!b){
 18         x=1;y=0;
 19         return a;
 20     }
 21     int ret=exgcd(b,a%b);
 22     int tmp=x;
 23     x=y;y=tmp-(a/b)*y;
 24     return ret;
 25 }
 26 
 27 int lcm(int a,int b){
 28     return a/exgcd(a,b)*b;
 29 }
 30 
 31 void ponySort(int l,int r){
 32     int i=l,j=r,mid=bi[(l+r)>>1];
 33     while(i<=j){
 34         while(bi[i]<mid) ++i;
 35         while(bi[j]>mid) --j;
 36         if(i<=j){
 37             C_swap(bi[i],bi[j]);
 38             C_swap(ai[i],ai[j]);
 39             ++i;--j;
 40         }
 41     }
 42     if(l<j) ponySort(l,j);
 43     if(i<r) ponySort(i,r);
 44     return;
 45 }
 46 
 47 int main(int argc,char *argv[],char *enc[])
 48 {
 49     scanf("%d",&k);
 50     for(int i=1;i<=k;++i)
 51         scanf("%d%d",&b[i],&a[i]);
 52     
 53     for(int i=1;i<=k;++i)
 54         printf("x ≡ %d (mod %d)\n",a[i],b[i]);
 55     printf("\n");
 56     
 57     for(int i=1;i<=k;++i)
 58         B=lcm(B,b[i]);
 59     
 60     for(int i=1;i<=k;++i){
 61         bi[i]=B/b[i];
 62         ai[i]=B/b[i]*a[i];
 63     }
 64     
 65     for(int i=1;i<=k;++i)
 66         printf("x*%d ≡ %d (mod %d)\n",bi[i],ai[i],B);
 67     printf("\n");
 68     
 69     ponySort(1,k);
 70     
 71     for(int i=1;i<=k;++i)
 72         printf("x*%d ≡ %d (mod %d)\n",bi[i],ai[i],B);
 73     printf("\n");
 74     
 75     for(int i=1;i<=k;++i)
 76     {
 77         if(tmpa!=ai[i] && tmpb==bi[i]){
 78             printf("NOPE\n");
 79             return 0;
 80         }
 81         tmpa=ai[i];
 82         tmpb=bi[i];
 83     }
 84     
 85     /* xi*bi[i] ≡ ai[i] (mod B) */
 86     
 87     for(int i=1;i<=k;++i){
 88         
 89         tmp=exgcd(bi[i],B);
 90         
 91         if(ai[i]%tmp!=0){
 92             printf("NOPE\n");
 93             return 0;
 94         }
 95         else{
 96             times=0;
 97             while(ai[i]%tmp==0){
 98                 ai[i]/=tmp;
 99                 ++times;
100             }
101             
102             if(tmp!=B){
103                 x*=ai[i];
104                 x=((x%(B/(tmp*times)))+(B/(tmp*times)))%(B/(tmp*times));
105                 printf("%d*%d ≡ %d (mod %d)\n",x,bi[i],ai[i]*times*tmp,B);
106             }
107             else{
108                 printf("NOPE\n");
109                 return 0;
110             }
111         }
112     }
113     
114     return 0;
115 }
116 /*
117 3
118 3 2
119 6 5
120 7 2
121 */

 

posted @ 2018-12-18 23:52  Antigonae  阅读(1492)  评论(0编辑  收藏  举报