扩展欧几里得和同余

Bézout's identity(裴蜀定理):给予二整数 $a$ 与 $b$, 必存在有整数 $x$ 与 $y$ 使得$ax + by = gcd(a,b)$。

扩展欧几里得算法:给予二整数 $a$ 与 $b$, 必存在有整数 $x$ 与 $y$ 使得$ax + by = gcd(a,b)$。有两个数$a,b$,对它们进行辗转相除法,可得它们的最大公约数——这是众所周知的。然后,收集辗转相除法中产生的式子,倒回去,可以得到$ax+by=gcd(a,b)$的整数解。

 1 int exgcd(int a, int b, int &x, int &y)
 2 {
 3     if(!b)
 4     {
 5         x = 1, y = 0;
 6         return a;
 7     }
 8     int d = exgcd(b, a % b, y, x);
 9     y -= a / b * x;
10     return d;
11 }

 

①当$b = 0$的时候,$ax = gcd(a, 0) = a$。所以这时候取$x = 1, y = 0$即可,并将a返回。

②这里取个巧将$x, y$交换一下位置,公式变为$by + (a mod b)x = d$。($d$为$gcd(a,b)$)

$by + (a\;mod \; b)x = d \leftrightarrow   by +(a - \lfloor \frac{a}{b} \rfloor b)x = d\leftrightarrow ax+b(y-\lfloor \frac{a}{b} \rfloor x) = d$

 

同余方程:

$ax\equiv b\left ( mod\;m \right )\leftrightarrow ax = my + b\leftrightarrow ax - my = b\leftrightarrow ax+my' = b$

该公式有解的条件就是$b\; mod\; d == 0$。其中$d$是$gcd(a, m)$,即$b$是最大公约数的倍数就有解,否则无解。

 

https://www.acwing.com/problem/content/204/

acwing 202.最幸运的数字

由题目,

$L\mid 88\cdot \cdot \cdot 8\leftrightarrow L\mid 8*11\cdot \cdot \cdot 1\leftrightarrow L\mid8*\frac{99\cdot \cdot \cdot 9}{9}\leftrightarrow L\mid 8*\frac{10^{x}-1}{8}
\leftrightarrow \frac{9L}{d}\mid {10^{x}-1}$,其中$d = gcd(L,8)$,意义为两边都除去8的质因子。如果左边没有,就不除,而右边除掉后依旧等价。

将$\frac{9L}{8}$看做一个常数$C$,转换为求一个最小的$x$使得$10^{x}\equiv 1\left ( mod\;C \right )$

由欧拉定理,有$a^{phi(n)}\equiv 1\left ( mod\;n \right )$,其中满足$gcd(a,n)= 1$。

首先,$10$和$C$必然互质,否则余数不可能为$1$, 所以如果$10$和$C$不互质,无解。

其次,我们可以知道所求的$x$必然是$phi(C)$的一个约数。

证明:假设$x$是满足$10^{x}\equiv 1\left ( mod\;C \right )$的最小数且不是$phi(C)$的约数,而欧拉定理也满足$10^{phi(C)}\equiv 1\left ( mod\;C \right )$,那么设$phi(C) = qx + r, 0<r<x$。

有$10^{qx+r}\equiv 1\left ( mod\;C \right )$,因为$10^{x}\equiv 1\left ( mod\;C \right )$,所以$10^{qx}\equiv 1\left ( mod\;C \right )$,所以得出$10^{r}\equiv 1\left ( mod\;C \right )$,就找到了一个比$x$更小的满足$10^{x}\equiv 1\left ( mod\;C \right )$的数,矛盾,所以$x$一定是$phi(C)$的一个约数。

又因为$x$要取最小,所以$x$一定是$phi(C)$的最小约数。

 所以本题需要求欧拉函数,求出$C$的欧拉函数,对其约数进行枚举,然后用快速幂判断。

需要注意的是,该题的数据很大,相乘过程中会爆掉long long,所以快速幂进行相乘的时候要使用龟速乘,防止溢出。

 1 #include <iostream>
 2 #include <algorithm>
 3 #include <cstdio>
 4 #include <cstring>
 5 
 6 using namespace std;
 7 
 8 typedef long long LL;
 9 
10 LL qmul(LL a, LL b, LL c)
11 {
12     LL res = 0;
13     while(b)
14     {
15         if(b & 1)res = (res + a) % c;
16         a = (a + a) % c;
17         b >>= 1;
18     }
19     return res;
20 }
21 
22 LL qmi(LL a, LL b, LL c)
23 {
24     LL res = 1;
25     while(b)
26     {
27         if(b & 1)res = qmul(res, a, c);
28         a = qmul(a, a, c);
29         b >>= 1;
30     }
31     return res;
32 }
33 
34 LL get_euler(LL n)
35 {
36     LL res = n;
37     for(LL i = 2 ; i <= n / i ; i ++)
38     {
39        if(n % i == 0)
40        {
41            while(n % i == 0)n /= i;
42            res = res / i * (i - 1);
43        }
44     }
45     if(n > 1)res = res / n * (n - 1);
46     return res;
47 }
48 
49 int main(){
50     int T = 1;
51     LL L;
52     while(cin >> L, L)
53     {
54         int d = 1;
55         while(L % (d * 2) == 0 && 2 * d <= 8)d *= 2;
56         
57         
58         LL C = 9 * L / d;
59         
60 
61         LL phi = get_euler(C);
62         
63 
64         LL res = 1e18;
65         if(C % 2 == 0 || C % 5 == 0)res = 0;
66         
67         for(LL i = 1 ; i <= phi / i ; i ++)
68             if(phi % i == 0)
69             {
70                 if(qmi(10, i, C) == 1)res = min(res, i);
71                 if(qmi(10, phi / i, C) == 1)res = min(res, phi / i);
72             }
73         printf("Case %d: %lld\n", T ++, res);
74     }
75     
76     
77     return 0;
78 }

 

 

中国剩余定理:

$m_1,m_2,m_3,m_4,\cdot \cdot \cdot m_k$两两互质。

$\left\{\begin{matrix}x\equiv a_1\left ( mod\;m_1 \right )
& \\ x\equiv a_2\left ( mod\;m_2 \right )
& \\ x\equiv a_3\left ( mod\;m_3 \right )
& \\ \cdot \cdot \cdot
& \\ \cdot \cdot \cdot
& \\ x\equiv a_k\left ( mod\;m_k \right )
&
\end{matrix}\right.$

$M = m_1m_2m_3\cdot \cdot \cdot m_k$

$M_i = \frac{M}{m_i}, t_i$是$M_i$模$m_i$的逆

即$M_i*t_i\equiv 1\left ( mod\;m_i \right )$

$x=a_1\cdot M_1\cdot t_1+a_2\cdot M_2\cdot t_2+a_1\cdot M_3\cdot t_3+\cdot \cdot \cdot +a_k\cdot M_k\cdot t_k$

 

https://www.acwing.com/problem/content/1300/

acwing 1298.曹冲养猪

 由题,$x\equiv B[i]\left ( mod \;A[i] \right )$

答案$x=B[1]\cdot M_1\cdot t_1+B[2]\cdot M_2\cdot t_2+B[3]\cdot M_3\cdot t_3+\cdot \cdot \cdot +B[k]\cdot M_k\cdot t_k$

其中,$M = A[1]* A[2]* A[3]\cdot \cdot \cdot A[k],M_i = \frac{M}{A[i]}$。

所以现在需要求得$t_i$,由 $M_i*t_i\equiv 1\left ( mod\;A[i] \right )\leftrightarrow M_i*t_i - A[i]*x = 1\leftrightarrow M_i*t_i+A[i]*x' = 1$,通过拓展欧几里得算法,可求出$t_i$。

迭代到最后求得答案。

 1 #include <iostream>
 2 #include <algorithm>
 3 
 4 using namespace std;
 5 
 6 typedef long long LL;
 7 
 8 const int N = 11;
 9 
10 int A[N], B[N];
11 int n;
12 
13 LL exgcd(LL a, LL b, LL &x, LL &y)
14 {
15     if(!b)
16     {
17         x = 1, y = 0;
18         return a;
19     }
20     LL d = exgcd(b, a % b, y, x);
21     y -= a / b * x;
22     return d;
23 }
24 
25 int main(){
26     cin >> n;
27     LL M = 1;
28     for(int i = 0 ; i < n ; i ++)
29     {
30         cin >> A[i] >> B[i];
31         M *= A[i];
32     }
33     
34     LL res = 0;
35     for(int i = 0 ; i < n ; i ++)
36     {
37         LL Mi = M / A[i];
38         LL ti, x;
39         exgcd(Mi, A[i], ti, x);
40         res += B[i] * Mi * ti;
41     }
42     
43     cout << (res % M + M) % M << endl;
44     return 0;
45 }

 

posted @ 2020-03-26 15:51  dzcixy  阅读(152)  评论(0)    收藏  举报