首页 > 其他分享 >数论基础

数论基础

时间:2024-02-15 11:24:01浏览次数:25  
标签:数论 基础 varphi times pmod ax 我们 equiv

数论:研究数与数之间的关系。如带余除法、因数倍数、同余整除等都是数论。

【筛法】

主要使用的筛法有两个:埃氏筛和欧拉筛(线性筛)。

使用筛法的原因很简单:对于一个数,我们要找它的因数不容易;但是对于一个因数,我们找它的倍数很简单。

【埃氏筛】

因为一个数的倍数一定不是质数,且任何数都能分解为若干质数之积,所以我们每找到一个质数,就把这个质数的所有倍数都标记为合数。

bool p[N] = {}; //p[i]=true表示i为质数
void shai() {
    p[0] = p[1] = false;
    for (int i = 2; i <= N; i++)
        p[i] = true;
    for (int i = 2; i <= N; i++)
        if (p[i]) {
            for (long long j = i; i * j <= N; j++) //删去所有倍数
                p[i * j] = false;
        }
}

注意:这里我们还有一个小优化,我们的 j 是从 i 开始枚举的,这是因为在 j < i 时,我们一定在 i 更小的时候就已经标记过 i * j 了。这样可以避免一些重复标记。

但是,我们发现埃氏筛依旧会出现重复标记的情况。例如 \(7\times 8=56\),我们会在 \(i=7\) 的时候筛一遍 \(56\),但是因为 \(8\) 有质因子 \(2\),所以在 \(i=2\) 时也会筛一遍 \(56\)。

因为有重复标记,所以埃氏筛的时间复杂度略高于 \(O(n)\)。当 \(n\) 很大的时候,可以明显看出它和 \(O(n)\) 的差距。

【欧拉筛】

我们希望埃氏筛可以进化到 \(O(n)\) 的复杂度。

上面埃氏筛慢的原因,就在于一个数被多次标记。而多次标记的原因,是我们分类分的不好。
我们在上面把所有合数分类,这个分类的方法是 “如果 \(x\) 是质数 \(p\) 的倍数,我们就把 \(x\) 分入 \(p\) 的类中”。
并且,每找到一个质数,我们就把该质数对应的分类中所有的数都打上合数标记。

显然,这样的分类方法可能会让一个数被分入多个类中,从而导致多次标记。现在,我们需要一个新的分类方法,可以把所有合数无遗漏无重复的分类。

考虑一个合数 \(x\) 会被分进谁的类中。如果能把 \(x\) 分进它的一个因数的类中,我们就可以很方便地打标记。

既然我们要 \(x\) 的因数,不如直接取最简单的情况:把 \(x\) 分进它最大的真因数 \(x'\) 的类中。
因为 \(x'\) 是最大真因数,所以 \(x'\) 到 \(x\) 一定只差了一个质因子,并且是 \(x\) 的最小质因子 \(p\)。

因为 \(p\) 是 \(x\) 的最小质因子,所以 \(x'\) 的质因子一定都大于等于 \(p\),于是我们可以枚举所有质数 \(a\),满足 \(a\) 小于等于 \(x'\) 的最小质因子,并把 \(x' \times a\) 打上标记。因为 \(x'\) 的最小质因子都大于等于 \(a\),所以这样可以保证 \(a\) 一定是 \(x'\times a\) 的最小质因数。

但是,对 \(x'\) 找最小质因子挺麻烦的。我们注意到这么一个性质:当 \(a\) 达到上限,也就是当 \(a=x'\) 的最小质因子时,\(a|x\)。因此,我们可以一直枚举 \(a\),如果 \(a|x'\) 就退出循环。

因为每个数都会唯一地分进一个类中,故这个算法是 \(O(n)\) 的。

int prime[60000006], cnt = 0; //cnt记录当前质数个数
bool p[60000005] = {};

void init() {
    for (int i = 2; i <= n; i++) {
        if (!p[i])
            prime[++cnt] = i;
			
            //j <= cnt:只能枚举当前找出来的质数
        for (int j = 1; j <= cnt && prime[j] <= n / i; j++) {
            p[i * prime[j]] = true;
            if (i % prime[j] == 0)
                break;
        }
    }
}

【运用线性筛思想解决问题】

分解质因数

对于一个数的分解质因数早已学过,但现在有了多次询问。

注意到,分解质因数的操作显然是一个可以递归的操作:如果要分解 \(x\),\(x\) 的最小质因数是 \(p\),那么相当于要分解 \(x/p\),并且在 \(x\) 的分解中加上一个 \(p\)。

考虑记录 \(mn[x]\) 表示 \(x\) 的最小质因数。如果能求出所有数的 \(mn[]\),我们就可以在 \(\log\) 的时间复杂度内回答一个询问。我们现在的任务就是预处理出 \(mn[]\) 数组。

还是一样的思路:对于一个数 \(x\),求 \(mn[x]\) 很难,但是求出所有 \(mn[]=x\) 的很简单。

我们把每一个数都分进它最小质因数对应的类中。但是这样还是难以解决,所以我们考虑把每一个数都分进它最大真因数对应的类中。然后在枚举到一个数的最大真因数 \(i\) 时,枚举所有可能的最小质因数 \(prime[j]\),并记录 \(mn[i\times prime[j]] = prime[j]\)。

可以发现,我们只需要在 p[i * prime[j]] = true 之后加上一句 mn[i * prime[j]] = prime[j] 即可。

因数个数与因数之和

因数个数的公式很简单:先分解质因数,然后每个质因数的指数加一再相乘。
但是,我们希望这个公式可以完成递推。

当我们已经知道了 \(n\) 的因数个数 \(f(n)\),考虑乘上一个质数 \(p\) 后的 \(f(np)\) 会怎么变化。

  1. \(n\) 中不含 \(p\),那么 \(f(np) = (1+1)\times f(n)\);

  2. \(n\) 中含 \(p\)。因为我们的 \(p\) 实际上枚举到 \(n\) 的最小质因数就退出了,所以我们只需要考虑当 \(n\) 乘上了 \(n\) 的最小质因数后的变化。

    我们只需要同时记录下 \(n\) 的最小质因数的次数 \(mn[n]\),就可以方便地让 \(f(np)=f(n)\div(mn[n]+1)\times (mn[np] + 1)\)。(显然 \(mn[np]=mn[n]+1\))

经过这么一系列的递推,我们就可以求出所有数的因数个数了。同理,因数和也可以求出来,只是公式不同而已。

【总结】

可以发现,我们在数论上的递推与动态规划时的递推并不相同。我们在数论上的递推通常不是由 \(k-1\) 推 \(k\),而是由 \(k/...\) 推 \(k\)。而线性筛就给我们提供了一个很好的递推方法:枚举每一个数的最大真因数,然后乘上一个最小质因数进行递推。

【积性函数】

若 \(f(ab)=f(a)\times f(b)|(a,b)=1\),称 \(f()\) 为积性函数。

例如上面的因数个数就是一个积性函数。

积性函数就意味着我们可以进行递推。

【欧拉函数】

定义 \(\varphi(n)\) 为 “小于 \(n\) 的数中与 \(n\) 互质的数的个数”。

若 \(n\) 的质因子为 \(p_1,p_2,...,p_k\),则 \(\varphi(n)=n\times \displaystyle \prod^k_{i=1}\frac{p_i-1}{p_i}\)。

因此,我们可以这样求欧拉函数。

如果我们要求 \(1\sim n\) 的 \(\varphi()\),肯定不能每一个都求一次。所以我们用上面欧拉筛的方法递推。

递推code

仪仗队

如果一个人位于 \((x,y)\),要想被看到,必须 \((x,y)=1\)。
于是这个题就变成了问有多少对数互质。当然,我们考虑一半即可,注意对角线只有一个能看到,特殊处理。

考虑对于每一列 \(a\),都要问比 \(a\) 小的有几个与 \(a\) 互质。所以答案就是 \(\varphi(1)+\varphi(2)+...+\varphi(n)\)。

【乘法逆元】

在题目中,我们经常需要取模。但是如果涉及除法,乱除可能导致答案错误。这时候,我们尝试用乘法在取模意义上代替除法。于是,乘法逆元诞生了。

若 \(ab \equiv 1 \pmod p\),则记 \(a=b^{-1}=\frac{1}{b},b=a^{-1}=\frac{1}{a}\),称 \(a,b\) 互为逆元。(模 \(p\) 意义下)

注意:只有 \(a,b\) 与 \(p\) 互质时才存在逆元。

逆元有什么用?如果我们要在模的意义下做除法,就相当于乘以除数的逆元。
那么如何快速求出逆元?

接下来我们做两件事。

  1. 若 \((a,p)=1\),求证:\(a^{-1}\mod p\) 存在且唯一。

  2. \(O(\log p)\) 的时间内求出 \(a^{-1}\mod p\)。

首先提出两个概念:完全剩余系和简化剩余系。

完全剩余系:简称完系。\(x\) 的完系为一个包含 \(x\) 个数的集合,满足集合中任何两个数模 \(x\) 的余数各不相同。

简化剩余系:简称简系。\(x\) 的简系为一个包含 \(\varphi(x)\) 个数的集合,满足集合中任何两个数模 \(x\) 的余数各不相同,且与 \(x\) 互质。

记 \(x\) 的完系为 \(R(x)\),\(x\) 的简系为 \(R'(x)\)。


下证:若 \((a,p)=1\),求证:\(a^{-1}\mod p\) 存在且唯一。

令 \(R'(p)=\{x_1,x_2,...,x_k\}\)。(\(k=\varphi(p)\))

显然,因为 \((a,p)=1\),所以 \(a\in R'(p)\)。如果 \(a^{-1}\) 存在,若 \((a^{-1},p)\neq 1\),则 \(a\times a^{-1} \neq 1\),矛盾。因此 \(a^{-1}\in R'(p)\)。

因为逆元就是相乘得一,所以我们考虑把所有东西都乘起来看看。

我们只需证明:对于任意 \(a\),\((a,p)=1\),则 \(ax_1,ax_2,...,ax_k\) 依然构成模 \(p\) 的简化剩余系。

  1. \(ax_1,ax_2,...,ax_k\) 有 \(\varphi(p)\) 个。且由于 \((a,p)=(x_i,p) = 1\),所以 \((ax_i, p)=1\)。

  2. 对于任意 \(i,j\),\(ax_i \not\equiv ax_j \pmod p\)。这是因为 \(ax_i\equiv ax_j \pmod p \iff p\mid ax_i-ax_j \iff p\mid a(x_i-x_j)\iff p\mid x_i-x_j\),矛盾。

因此,\(ax_1,ax_2,...,ax_k\) 也是模 \(p\) 的简系。显然简系中有一个 \(1\)。所以 \(x_1,x_2,...,x_k\) 中恰有一个是 \(a^{-1}\)。

证毕。


怎么求乘法逆元?

欧拉定理:对于 \((a,p) = 1\),有 \(a^{\varphi(p)}\equiv 1 \pmod p\)。

证明:考虑模 \(p\) 的简化剩余系 \(x_1,x_2,...,x_k\)。由上面知 \(ax_1,ax_2,...,ax_k\) 也是简系。

所以 \(\displaystyle\prod^k_{i=1} x_i\equiv ax_1\times ax_2 \times ... \times ax_k \pmod p\)。

记 \(\displaystyle\prod^k_{i=1} x_i = X\),则 \(X\equiv a^{\varphi(p)}X\pmod p\)。

又 \((X,p)=1,(a^{\varphi(p)},p)=1\),所以 \(X,a^{\varphi(p)}\in R'(p)\)。

故,若 \(a^{\varphi(p)}\not\equiv 1\),则 \(a^{\varphi(p)}X\not\equiv 1\cdot X\not\equiv X\),矛盾。

所以 \(a^{\varphi(p)}\equiv 1\pmod p\),证毕。

由于 \(a^{\varphi(p)}\equiv 1\pmod p\),所以 \(a\times a^{\varphi(p)-1}\equiv 1\),所以 \(a^{-1}=a^{\varphi(p)-1}\)。用快速幂求解即可。

【连续的乘法逆元】

连续乘法逆元

注意要求模数为质数。

如果对于每一个数,都用 \(a^{\varphi(p)-1}\) 算,就太慢了。

我们希望可以重复利用之前求出来的数据。

假设已知 \(1\sim (k-1)\) 的逆元,求 \(k\) 的逆元。\((\!\!\!\!\mod p)\)

考虑带余除法:\(p\div k=t\cdot\cdot\cdot\cdot\cdot\cdot \;r\;(0\leq r < k)\)

\(p=kt+r,kt+r\equiv 0 \pmod p\)。

两边同时乘 \(k^{-1}r^{-1}\)。利用逆元性质:相乘得一。

\(t\cdot r^{-1}+k^{-1}\equiv 0\pmod p\)。

\(k^{-1}\equiv -t\cdot r^{-1} \equiv -(p/k)\,(p \!\!\!\mod k)^{-1} \pmod p\)

所以,\(k^{-1}\) 可以用 \((p\,\%\,k)^{-1}\) 推出来。

初始设立 \(inv[1]=1\),然后一路递推到 \(inv[n]\)。


带余除法:\(a\div p = t \dots\dots r\,(0\leq r<p)\),\(a=pt+r\)。

如果我们想求 \(a\) 的某种属性,可以考虑用 \(p,t,r\) 三者的属性推出来。

【BSGS】

模板 BSGS

给定 \(b\)、\(p\)、\(n\),求 \(l\) 使得 \(b^l \equiv n \pmod p\)

首先有一个枚举的想法,\(O(p)\)。

然后想到:

一个一个往前枚举太慢了,如果能先大幅度跨,然后再小幅度调整,时间就会快很多。


设 \(t=[\sqrt p],l=at+r(0\leq r < t)\)。

因为 \(l\) 显然 \(\leq p\),\(t=[\sqrt p]\),所以 \(a\) 的级别是 \(\sqrt p\);因为 \(r<t\),所以 \(r\) 的级别也是 \(\sqrt p\)。最终的复杂度是 \(O(\sqrt p)\) 的,是一个比较好的复杂度。

考虑用带余除法的方式转换式子。

\(b^l\equiv b^{at+r}\equiv (b^t)^a\times b^r \equiv n\pmod p\)。

我们枚举 \(a\),考虑怎么求 \(r\)。当 \(a=a_0\) 时:

\((b^t)^{a_0}\times b^r\equiv n,b^r\equiv n\times [(b^t)^{a_0}]^{-1}\)。

如果我们能找到一个 \(r\) 满足 \(b^r\equiv n\times [(b^t)^{a_0}]^{-1}\),那么这个 \(r\) 和 \(a_0\) 组成一组可行的解,然后就能直接通过 \(l=at+r\) 求出对应的 \(l\)。

但是,如果不能快速找到 \(r\),时间并没有优化。那我们怎么快速找到 \(r\) ?

建立一个 map,索引时 \(n\times [(b^t)^{a_0}]^{-1}\),键值是 \(r\)。这样当我们算出 \(n\times [(b^t)^{a_0}]^{-1}\) 时,我们可以立刻用 mp[\(\;n\times [(b^t)^{a_0}]^{-1}\;\)] 查询对应的 \(r\)。

【具体实现时的修改】

在具体实现时,我们让 \(l=at-r(1\leq r\leq t)\)。

\(b^l=b^{at-r}=(b^t)^a\div b^r\equiv n\)。

\(b^r\equiv (b^t)^a\times n^{-1}\)。

我们让 map[ \(b^r\) ] \(\rightarrow r\),这样就可以用 map[ \((b^t)^a\times n^{-1}\) ] 快速求 \(r\)。

当然,我们也可以让 map[ \(b^r\times n\) ] \(\rightarrow r\),这样我们的式子就应该是 \(b^r\times n \equiv (b^t)^a\),调用 map[ \((b^t)^a\) ] \(\rightarrow r\) 进行查询。

至于 \(l=at-r\) 而非 \(l=at+r\) 的原因,是因为 \(map\) 里面查询不到会返回 0,如果 \(0\leq r < t\),会混淆不存在和 \(r=0\)。

code

【裴蜀定理】

裴蜀定理

裴蜀定理:\(\displaystyle \sum_{i=1}^n A_ix_i = gcd(A_1,A_2,...,A_n)\) 一定有解。

二元形式:若 \((a,b)=1\),则 \(ax+by=1\) 有解。

考虑模 \(b\) 的简系,这个简系乘 \(a\) 也是简系,其中必有一个 1。所以存在 \(ax=bk+1\),此时令 \(y=-k\) 即可。

【拓展欧几里得算法】

【模板】二元一次方程组

判断无解:裴蜀定理,\(gcd(a,b)\) 是否整除 \(c\) 。

接下来尝试寻找一组整数解。一个简单的想法显然可以枚举 \(x\),\(O(\min(a,b))\)。慢,考虑优化。

众所周知,辗转相除法可以求出 \(gcd(a,b)\)。那我们能否在辗转相除的过程中,顺便求出对应的解 \((x,y)\) 呢?

辗转相除法:不妨 \(a\geq b,gcd(a,b)=gcd(b,a\%b)\)。

对 \(ax+by=gcd(a,b)\) 的方程,考虑用辗转相除法递归:转化为 \(bx_0+(a\%b)y_0=gcd(b,a\%b)\),用 \(x_0,y_0\) 推出 \(x,y\)。

这么做之所以好,是因为等式左侧的关系很明显,而右侧始终相等。

同样地,考虑辗转相除法的结束条件:\(a,b\) 中,一个是 0,另一个是最大公因数。
当我们递归结束时,方程变为 \(gcd(a,b)x_0+0\cdot y_0=gcd(a,b)\)。

显然此时的有解 \((1,0)\)。

现在我们希望通过这一层的解推出上一层的解。
即已知 \(bx+(a\%b)y=gcd(a,b)\) 有解 \((x_0,y_0)\),求 \(ax+by=gcd(a,b)\) 的解 \((x,y)\)。

因为我们想要 \(b,a\%b\),所以考虑把 \(a\) 拆掉,\(a=[\frac{a}{b}]\times b+a\%b\)。
现在的方程变为 \([[\frac{a}{b}]]\times b+(a\%b)]x+by=gcd(a,b)\)。

拆括号,\(b\cdot[\;[\frac{a}{b}]x+y\;]+(a\%b)x=gcd(a,b)\)。这不就是上一层的形式吗?

所以,令 \([\frac{a}{b}]x+y=x_0,x=y_0\) 即可。\((x,y)=(y_0,x_0-[\frac{a}{b}]y_0)\)。

【中国剩余定理】

中国剩余定理(孙子定理)

记 \(M=\displaystyle\prod^n_{i=1} p_i,M_i=M/p_i\)。显然 \((M,M_i)=1\)。

不妨设 \(M_i \;\rm mod\;p_i\) 逆元 \(M_i^{-1}\)。

有特解:\(x_0=\displaystyle\sum^n_{i=1} a_iM_iM_i^{-1}\)。

正确性:\(x_0 \equiv a_i\pmod {p_i}\) 吗? \(x_0\) 中的 \(a_iM_iM_i^{-1}\) 贡献 \(a_i\) 的余数,其余项的 \(M_{()}\) 都包含 \(p_i\),所以最终的余数就是 \(a_i\)。

通解:\(x=x_0+k\cdot M(k\in Z)\)。

【阶与原根】

阶:\(a\;\rm mod\;p\) 的阶为最小的 \(r\) 使得 \(a^r\equiv 1\pmod p\)。

性质一:若 \(a^k\equiv 1\pmod p\),必有 \(r\mid k\)。

证明:若 \(r\mid\!\!\!\!\,\not \;\;k\),记 \(k=tr+z(1\leq z<r)\),则 \(a^z\equiv 1\pmod p\) 且 \(z<r\),与 \(r\) 最小矛盾。

性质二:\(a^k\equiv a^{k-r}\pmod p\)。证明显然。

由于 \(a^{\varphi(p)}\equiv 1\pmod p\),所以 \(r\mid \varphi(p)\)。

如果 \(r=\varphi(p)\),称 \(r\) 为原根。

原根的性质:\(a^1\sim a^r\; \rm mod\;p\) 刚好构成一个 \(\rm mod\;p\) 的简系。

标签:数论,基础,varphi,times,pmod,ax,我们,equiv
From: https://www.cnblogs.com/FLY-lai/p/18016078

相关文章

  • 线性代数基础
    元素:一个个体,一般是一个数。【向量】向量:一组元素,向量\(a\)记作\(\vec{a}\)。我们只在乎向量的方向和大小,并不在乎向量的起点和终点。定义:\(n\)维向量,即\(\vec{a}\)中包含\(n\)个元素。向量的运算:向量的大小:\(|\vec{a}|\)。向量加减:只有两个规模相等的向量的......
  • 组合基础
    OI中的组合,基本指组合计数。组合极值一般是贪心题或者dp题。【组合数】组合数\(C^m_n=(^n_m)\)。注意:求逆元前,请一定判断清楚,是否可能不存在逆元!!!\(C^m_n=C^m_{n-1}+C^{m-1}_{n-1}\)。c[n][m]=c[n-1][m]+c[n-1][m-1];这个方法主要问题在于空间。优点:可以......
  • 基础图论笔记
    二分图  染色法  例题ACwing860-染色法判断二分图(染色法)-CSDN博客给定一个n个点m条边的无向图,图中可能存在重边和自环。请你判断这个图是否是二分图。输入格式第一行包含两个整数n和m。接下来m行,每行包含两个整数u和v,表示点u和点v之间存在一条边。输出格式如......
  • Lag-Llama:第一个时间序列预测的开源基础模型介绍和性能测试
    2023年10月,我们发表了一篇关于TimeGPT的文章,TimeGPT是时间序列预测的第一个基础模型之一,具有零样本推理、异常检测和共形预测能力。虽然TimeGPT是一个专有模型,只能通过API访问。但是它还是引发了对时间序列基础模型的更多研究。到了2024年2月,已经有了一个用于时间序列预测的开源......
  • 《从基础认识相对论的错误》 回复
    《从基础认识相对论的错误》      https://tieba.baidu.com/p/8895510201     这帖是你昨天发的, 10天前,你发了  《相对论对物理理论的影响是什么?》   https://tieba.baidu.com/p/8885351309  , 半年前,  我发过《@东方已晓的反相观点》......
  • python基础学习6-第三方模块
    自定义模块优先级大于系统模块模块分为系统模块,自定义模块,第三方模块导入方式import模块名称[as别名]from模块名称import变量/函数/类*包的导入import包名.模块名as别名form包名import模块名as别名form包名.模块名import函数/变量/类*主程序运行i......
  • Java基础
    java基础一、注释二、标识符和关键字关键字:标识符Java所有的组成部分都需要名字。类名、变量名以及方法名都被称为标识符。标识符注意点:所有的标识符都应以字母(A-Z或者a-z),美元符($)、或者下划线(_)开始首字符之后可以是字母(A-Z或者a-z),美元符($)、下划线(_)或数字的任何字符组合......
  • DFS基础与回溯
    回溯法简介回溯法一般使用DFS(深度优先搜索(递归))实现,DFS是一种遍历或搜索图,树或图像等数据结构的算法。上述数据结构不保存下来就是回溯法。常见的是搜索树,排列型搜索树(节点数一般为n!)与子集型搜索树(节点数一般为2n)。DFS从起始点开始,沿着一条路尽可能深入,直到无法继续回溯到上......
  • 基础数据结构笔记
    链表与邻接表:树与图的存储 单链表  画个图就很好理解了   例题826.单链表acwing——826.单链表_awcing826-CSDN博客实现一个单链表,链表初始为空,支持三种操作:(1)向链表头插入一个数;(2)删除第k个插入的数后面的数;(3)在第k个插入的数后插入一个数现在要......
  • 第二章 语法基础
       目  录1.第一个Python程序 2.数据与数据类型 3.数据类型转换 4.标识符 5.变量 6.常量 7.Python运算符 8.表达式 9.语句 10.实例: 语法基础    任何一段计算机程序都是由一组计算机能够理解的指令构成,其中每条指令都表现为遵循......