【20170921】(Unfinished)2017暑假北京学习 day 2

(本文参考了 镜外之主  dalao 的博客)

 

一、引入 线性同余方程组

    诸多个形如 ax ≡ b (mod p) 的,以x为未知数的一次方程,组成的方程组。

 

二、引入 数论倒数

  引入: 

    首先,在mod中,仅有加、减、乘法对于mod存在“封闭性”

 

    即

    ( a + b ) %p = (a %p )+ ( b %p )   √

    ( a - b ) %p = (a %p )- ( b %p )   √

    ( a × b ) %p = (a %p )× ( b %p )   √

    ( a / b ) %p = (a %p )/ ( b %p )   ×

    

    在实际运算中,由于某些过程中间结果过大,long long int都存不下,我们不得不边计算边求余,这时如果我们遇见除法,是不是就完蛋了呢?

    当然不是 i(>o<)i,我们拥有一个秘密武器——数论倒数

 

  定义:

    如果(a,m)=1且存在唯一的b使得a×b≡1(mod m)且1≤b<m,即b使得 a ≡(1/b)(mod m),则称b为a在模m意义下的数论倒数,记为inv(a)。

    简单来说,就是(a  /  b) % p = (a * inv(a) ) % p = (a % p * inv(a) % p) % p

    ——这样我们就可以在mod中做"除法"啦 ~(—v—*)~

  !Warning:当且仅当(a,p)=1,即a,p互质的时候,a才有在%p环境下的数论倒数!

 

 

 

      

三、中国剩余定理——解 线性同余方程组

 

 

   引入

      用现代数学的语言来说明的话,中国剩余定理给出了以下的一元线性同余方程组:

 

      

 

      有解的判定条件,并用构造法给出了在有解情况下解的具体形式。

 

 

 

   中国剩余定理 说明:

      方程组有解前提:整数m1,m2, ... ,m两两互质

 1 int isHasAnswer(long long int *m)
 2 //return 0 == No answer
 3 //return 1 == Has answer
 4 {
 5     int i,j;
 6     int flag=0;
 7     for(i=1;i<=len_m;i++)
 8         for(j=i+1;j<=len_m;j++)
 9         {
10             if(gcd(m[i],m[j])==1)//m[i]与m[j]互质
11             {
12                 flag=1;
13                 return 0;
14             }
15         }
16     return 1;
17 } 

      则对任意的整数:a1,a2, ... ,an方程组有解,并且通解可以用如下方式构造得到:

 

      设     是整数m1,m2, ... ,mn的乘积,

 

      并设 
  是除了 mi 以外的 n- 1 个整数的乘积。

 

 

      设 ti
的数论倒数(
意义下的逆元)

 

 

        即
 
 

 

      故方程组
的通解形式为
        

      在模的意义下,方程组只有一个解:

        

 

      

 

四、扩展欧几里得算法

 

 

  用途:

    扩展欧几里得算法 是用来在已知a, b求解一组x,y

    使它们满足贝祖等式ax+by = gcd(a, b) =d(一定存在整数解,根据数论中的相关定理)。

 

  时间复杂度:

    求 n 个不超过 m 的正整数的最大公约数—— O(n+logm)。

 

  代码:

 1 /*已知a,b(a>b),求解x,y,满足ax+by=gcd(a,b),并同时返回gcd(a,b)*/
 2 int exGcd(int a,int b,int &x,int &y)//x,y使用了引用传递的方式 
 3 {
 4     if(b==0)
 5     {
 6         x=1;
 7         y=0; 
 8     /*
 9     当a%b==0时,显然gcd(a,b)=b,
10     所以b = gcd(a,b) = gcd(b,a%b) = gcd(b,0)
11     此时显然 b*1+0*0 = gcd(b,0) = gcd(a,b)
12     故 x=1,y=0
13     */
14     }
15     else
16     {
17         //g=gcd(a,b)
18         int g = exGcd(b,a%b,x,y);
19         int t = x;
20         x = y;
21         y = t - a/b * y;
22         return g;
23         /*
24         求解 x,y的方法的理解:
25       设 a>b。
26       1,显然当 b=0,gcd(a,b)=a。此时 x=1,y=0;
27       2,a>b>0 时
28       设 ax1+ by1= gcd(a,b);
29       bx2+ (a mod b)y2= gcd(b,a mod b);
30       根据朴素的欧几里德原理有 gcd(a,b) = gcd(b,a mod b);
31       则:ax1+ by1= bx2+ (a mod b)y2;
32       即:ax1+ by1= bx2+ (a - [a / b] * b)y2=ay2+ bx2- [a / b] * by2;
33       也就是ax1+ by1 == ay2+ b(x2- [a / b] *y2);
34       根据恒等定理得:
35     
36         x1=y2;
37         y1=x2- [a / b] *y2;
38     
39       这样我们就得到了求解 x1,y1 的方法:x1,y1 的值基于 x2,y2.
40       上面的思想是以递归定义的,因为 gcd 不断的递归求解,一定会有个时候 b=0,
41 所以递归可以结束。
42         */
43     }
44 }

 

  针对例题:

    poj1601-青蛙的约会

原文地址:https://www.cnblogs.com/CXSheng/p/7532519.html