小鼠论

小数论

若无特殊说明 \((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)
posted @ 2025-12-05 14:11  闫柏军  阅读(0)  评论(0)    收藏  举报