扩展欧几里得和同余
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 }

浙公网安备 33010602011771号