小鼠论
小数论
若无特殊说明 \((x, y) = gcd(x, y), d = (x, y), [x, y] = lcm(x, y)\)
唯一分解定理
\(x = p_1^{α_1} \times p_2^{α_2} \times ... \times p_k^{α_k}\)
一个数的约数个数
约数个数 = $ (α_1 + 1) \times (α_2 + 1) \times ... \times (α_k + 1)$
证明:每个质因子选0 ~ α个。
一个数的约数之和
约数之和 = $ (p_1^0 + p_1^1 + ... + p_1^{α_1}) \times ... \times (p_k^0 + p_k^1 + ... + p_k^{α_k})$
证明:展开即可。
辗转相除法
$ (a, b) = (b, a % b) $
证明即证:
a,b的每一个共约数是右边的共约数
b,a%b的每一个公约数是左边的共约数
return b == 0 ? a : gcd(b, a % b);
欧拉函数
$\varphi(x) = $ \(1\) ~ \(x\) 中与 \(x\) 互质的数的个数。
根号复杂度 求解一个数的欧拉函数
\(\varphi(x) = x \times (1 - \frac{1}{p_1}) \times (1 - \frac{1}{p_2}) \times ... \times (1 - \frac{1}{p_k})\)
证明:容斥原理
先从 \(x\) 中去掉所有 $p_1, p_2 ... p_k $的倍数。
即 \(x - \frac{x}{p1} - \frac{x}{p2} - ... - \frac{x}{pk}\)。
注意到如果一个数即是 \(p_1\) 也是 \(p_2\) 的倍数,那么他被加了两次,所以要减掉。
如果一个数是 \(p_1 * p_2 * p_3\) 的倍数,那么他被加了3次,减了3次,而本应该减去一次,所以要减掉。
...
将原公式展开,即可得到容斥原理的式子。
线性筛求欧拉函数
首先质数 \(p\) 的欧拉函数为 \(\varphi(p) = p - 1\) 这是显然的。
然后我们看如如果 \(i \% p_j == 0 时 i \times p_j 的欧拉函数\) ,此时 \(p_j\) 为 \(i\) 的最小质因子,
因此 \(\varphi(i*p_j) 和 \varphi(i) 只差了 p_j\)
因为他们的质因子全部相同。 (根据公式只差了最前面的一项)
那么对于 \(i \% p_j\) != 0的呢。
这次\(\varphi(i*p_j) 和 \varphi(i) 差了 p_j 和 (1 - \frac{1}{p_j})\)。
把公式写出来看就明白了。
欧拉定理(费马小定理的爸爸
若 \(a\) 与 \(m\) 互质,则有 \(a^{\varphi(m)} \equiv 1 \pmod{m}\)。
证明使用完全剩余系。
设\(b_1, b_2, b_3 ... b_{\varphi(m)}\) 为 1 ~ m中与
m互质的所有数(显然互不相同
那么有\(a\times b_1, a\times b_2 ...... a\times b_{\varphi(m)}\) 在 % m 的意义下与 \(b_1, b_2...b_{\varphi(m)}\) 完全相同。
证明:首先显然\(a\times b_1, a\times b_2 ...... a\times b_{\varphi(m)}\) 都与 m 互质,所以只需证明他们也两两不同即可。
那么假设其中
\(a\times b_i \equiv a\times b_j \pmod{m}\)
\(a\times (b_i - b_j) \equiv 0 \pmod{m}\)
\(a\) 与m互质。
\(b_i - b_j \equiv 0 \pmod{m}\)
\(b_i \equiv b_j \pmod{m}\)
与上述b互不相同矛盾,完证。
那么有他们的乘积在% p意义下同余。
\(b_1 \times b_2 \times ...\times b_{\varphi(m)} \equiv (a\times b_1) \times (a\times b_2) \times ... \times (a\times b_{\varphi(m)}) \pmod{m}\)
\(b_1 \times b_2 \times ...\times b_{\varphi(m)} \equiv a^{\varphi(m)} \times b_1 \times b_2 \times ...\times b_{\varphi(m)} \pmod{m}\)
\(a^{\varphi(m)} \equiv 1 \pmod{m}\)
证毕。
逆元
求 \(a\) 在 mod p的意义下的逆元。
\(要求a 与 p 互质\)
也就是要求\(x\) 满足 \(a \times x \equiv 1 \pmod{p}\)
先只看p为质数,我们有
\(a^{p-1} \equiv 1 \pmod{p}\)
\(a \times a^{p-2} \equiv 1 \pmod{p}\)
在p为质数的前提下 \(a^{p-2}\) 即为 \(a\) 的乘法逆元。
也就是在求 \(\frac{b}{a} \pmod{p}\) 时我们将整个式子乘上 \(a \times a^{p - 2}\) 这样就得到了原式子的答案(因为你乘的东西%p同余1 所以相当于没乘)
当p不为质数时,就用欧拉定理\(a^{\varphi(p)} \equiv 1 \pmod{p}\)。
裴蜀定理
对于任意正整数\(a, b\)都一定存在非零整数使得
\(ax + by = (a, b)\)
\((a, b)\) 也是 a, b能组合出来的最小的正整数。
同时\(ax + by\)一定是\((a, b)\)的倍数。
因为a是d倍数,b是d的倍数,他们的若干倍也一定是d的倍数,并且最小的那个就是d。(正整数)
感性理解吧,以后补证明。
扩展欧几里得
就是求裴蜀定理中的\(x, y\)的。
int exgcd(int a, int b, int &x, int &y)
{
if(b == 0)
{
x = 1, y = 0; // 其实y可以任意
return a;
}
int d = exgcd(b, a%b, y, x);
y -= a / b * x;
return d;
}
当b = 0时 求\(ax + by = (a, b)\)
\(ax = a\)
所以\(x\)必须等于1, 而\(y\)随意。
对于b!=0的情况,那么我们采用递归的方式。
先求出
\(by + (a\%b)x = (a, b)\)
时的x,y。
然后解一下。
\(by + (a-\lfloor \frac{a}{b} \rfloor \times b)x = (a, b)\)
\(ax + b(y - \lfloor \frac{a}{b} \rfloor \times x) = (a, b)\)
所以只需将 \(y \leftarrow y - \lfloor \frac{a}{b} \rfloor \times x\)。
求通解
假设已经求出\(ax_0 + by_0 = d\)
(\(d = (a, b)\))
那么通解为
\(\begin{cases} x = x_0 - \frac{b}{d}\times k\\ y = y_0 + \frac{a}{d}\times k \end{cases}\)
\(k\) 为任意整数。
线性同余方程
exgcd的简单应用。
给定\(a, b, m\) 求一 \(x\) 使得 \(ax \equiv b \pmod{m}\)
b%=m
等价于
\(ax = b + m\times y\)
\(ax - my= b\)
\(y_0 = -y\)
\(ax + my_0= b\)
这不就是扩展欧几里得。
有解条件为b是d的倍数。
求出 =d 的解后将x, y乘个 \(\frac{b}{d}\) 即可。
中国剩余定理 CRT
讲的比较好的 link
这篇讲的是比较偏向怎么想到的,下面我来概括的说下。
\(\begin{cases} x \equiv a_1 \pmod{m_1}\\ x \equiv a_2 \pmod{m_2}\\ ...\\ x \equiv a_k \pmod{m_k} \end{cases}\)
\(m\) 两两互质,求满足条件的 \(x\) 的最小值。
设 \(M = m_1\times m_2 \times ... \times m_k\)
\(M_i = \frac{M}{m_i}\) 也就是除了 \(m_i\) 其他 \(m\) 的乘积。
再令 \(M_i^{-1}\) 为 \(M_i的逆元(模m_i意义下)\)
显然 \(m_i 与 M_i\) 互质,因为 \(m\) 两两互质,但是 \(m_i\) 不一定为质数,所以需要用扩展欧几里得或者欧拉定理求逆元。
那么我们有
\(x = a_1 * M_1 * M_1^{-1} + a_2 * M_2 * M_2^{-1} + ... + a_k * M_k * M_k^{-1}\)
这个数显然满足所有限制。
我们看 \(\% m_1的情况,第一项显然为a_1, 后面的项M中都有m_1所以后面每一项都是0\)
要求最小 \(\pmod{M}\) 即可。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define rep(i, a, b) for(int i = (a); i <= (b); i ++ )
int a[11], b[11]; ll M[11], inv[11];
ll exgcd(ll a, ll b, ll &x, ll &y, ll mod)
{
if(b == 0)
{
x = 1, y = 0;
return a;
}
int d = exgcd(b, a % b, y, x, mod);
y -= a / b * x;
return d;
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int n; cin >> n;
ll MM = 1;
rep(i, 1, n)
{
cin >> b[i] >> a[i];
MM *= b[i];
}
ll ans = 0;
rep(i, 1, n)
{
M[i] = MM / b[i];
ll x, y;
exgcd(M[i], b[i], x, y, b[i]);
inv[i] = (x % b[i] + b[i]) % b[i];
ans = ((__int128)ans + (__int128)a[i] % MM * M[i] % MM * inv[i] % MM) % MM;
}
cout << ans;
return 0;
}
代码时间,曹冲养猪。
其实, 设 \(M =∏mi\),那么如果 \(x\) 是解的话,x + M 必然也是解。而 \(x + t, 1 ≤ t < M\) 必然不可能是解。所以最后答案的形式一定是 \(x ≡ t \pmod{M}\)。这也启示我们,只要找到一个特解,就能找到所有的解。
扩展中国剩余定理 exCRT
综合性比较强
在CRT的基础上,现在不保证 m 两两互质,考虑怎么求呢。
我们先考虑只有两个式子,可以怎么化简化简。
\(\begin{cases} x \equiv a_1 \pmod{m_1}\\ x \equiv a_2 \pmod{m_2}\\ \end{cases}\)
\(\begin{cases} x \% m_1 = a_1\\ x \% m_2 = a_2\\ \end{cases}\)
\(\begin{cases} x = k_1m_1 + a_1\\ x = k_2m_2 + a_2\\ \end{cases}\)
\(k_1m_1 + a_1 = k_2m_2 + a_2\)
\(k_1m_1 - k_2m_2 = a_2 - a_1\)
使用扩展欧几里得可以求出 \(k_1, k_2\)。
有解当且仅当 \(d | (a_2 - a_1)\)。
现在 \(x = k_1m_1 + a_1\)。
然而 \(k_1\) 的取值为 \(k_1 + k\frac{m_2}{d}, k∈ Z\)
所以 \(x = (k_1 + k\frac{m_2}{d})m_1 + a_1\)
\(x = (k_1 + k\frac{m_2}{d})m_1 + a_1\)
\(x = k_1m_1 + k\frac{m_2m_1}{d} + a_1\)
\(x = k_1m_1 + a_1 + k[m1, m2]\)
\(k_1m_1 + a_1\) 是定值,称之为新的 \(a\)。
后面那一项称之为新的 \(km\)。至此我们就将两项合并成为一项了。
只需合并 \(n - 1\) 次即可得到最终的 \(x = km + a\)
代码在补。 写的太丑了。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define rep(i, a, b) for(int i = (a); i <= (b); i ++ )
ll exgcd(ll a, ll b, ll &x, ll &y)
{
if(! b)
{
x = 1, y = 0;
return a;
}
ll d = exgcd(b, a % b, y, x);
y -= a / b * x;
return d;
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int n; cin >> n;
ll a1, m1; cin >> a1 >> m1;
ll a2, m2; bool fl = true;
rep(i, 1, n - 1)
{
cin >> a2 >> m2;
ll x, y;
ll d = exgcd(a1, a2, x, y);
if((m2 - m1) % d) {fl = false; break;}
ll lst = abs(a1);
a1 = abs(a1 / d * a2);
ll t = a2 / d;
x = (((__int128)x * (m2 - m1) / d) % t + t) % t;
m1 = (m1 + (__int128)x*lst%a1) % a1;
}
if(fl) cout << (m1 % a1 + a1) % a1 << '\n';
else cout << "-1\n";
return 0;
}
线性求阶乘逆元
inv[i] = inv[i + 1] * (i + 1)

浙公网安备 33010602011771号