Loading

【瞎口胡】基础数学 1 快速幂 整除 最大公约数

写在前面

真的没啥可看的,就当我是给一万年后我校学 OI 的小朋友们写的(如果那时候还有的话)。

普通选手还是别看了,浪费时间,而且体现了我的菜。

符号说明

以下符号都是文中不会解释的。

\(\sum\):求和符号,\(\sum _{i=1}^{n} d_i = d_1 + d_2 + ... + d_n\)\(\sum_{d|n} d=\) \(n\) 的正约数和。

\(\prod\):连乘积符号,\(\prod_{i=1}^{n} i = 1 \times 2 \times ... \times n\)

\(\text{mod}\):模。\(x \mod y\) 即为 \(x\) 除以 \(y\) 的余数,\(2 \mod 3 = 2,8 \mod 4 = 0,5 \mod 3 = 2\)

\(\min\{\},\max\{\}\):最小值,最大值。这都不会还来看这篇文章?

快速幂

快速幂利用了整数乘法的结合律。\(a^{b+c} = a^b \times a^c\),利用这个思想把 \(a^c \mod p\)\(O(\log c)\) 的时间内求出。

具体的思想是把 \(c\) 二进制拆分成 \(2^{r_1}+2^{r_2}+2^{r_3}+...2^{r_n}\),其中 \(r_i\) 两两不同。再计算所有 \(a^{2^{r_1}}\) 的乘积,就得到了 \(a^c\)

模板题 Luogu P1226 Code

# include <bits/stdc++.h>
# define int long long 

const int N=100010,INF=0x3f3f3f3f;

int b,p,k;

inline int read(void){
	int res,f=1;
	char c;
	while((c=getchar())<'0'||c>'9')
		if(c=='-')f=-1;
	res=c-48;
	while((c=getchar())>='0'&&c<='9')
		res=res*10+c-48;
	return res*f;
}
inline int qpow(int d,int p){ d^p mod k
	int ans=1;
	while(p){
		if(p&1){ // 找出 p 中二进制下为 1 的位
			ans=ans*d%k;
		}
		p>>=1,d=d*d%k;	
	}
	return ans%k; // 大多时候可以不用取模 只有 k = 1 的时候需要这么做
}
# undef int
int main(void){
# define int long long
	b=read(),p=read(),k=read();
	printf("%lld^%lld mod %lld=%lld",b,p,k,qpow(b,p)); 
	return 0;
}

整除

基本知识

对于非负整数 \(a\) 和正整数 \(b\),如果 \(\frac ab\) 是整数(即: \(a\) 除以 \(b\) 的余数是 \(0\)),那么我们称 \(b\) 整除 \(a\),记作 \(b \mid a\);称 \(b\)\(a\)约数(或称因数因子),\(a\)\(b\)倍数。例如:\(2 \mid 114514\)\(2\)\(114514\) 的约数,\(114514\)\(2\) 的倍数。

如果 \(b\) 不整除 \(a\),则记作 \(b \nmid a\)。例如 \(114514 \nmid 1919810\)

\(a\) 除以 \(b\) 的余数记作 \(a \mod b\)。例如 \(9 \mod 7=2,13 \mod 4 =1\)

  • 求出正整数 \(n\) 的所有约数

    容易发现 \(n\) 的约数成对出现,若 \(i|n\),则 \(\frac ni|n\)

    考虑枚举 \([1,\sqrt n]\) 范围内的每一个正整数,逐个判断是否是 \(n\) 的约数。

    时间复杂度 \(O(\sqrt n)\)

    std::vector <int> A;
    for(int i=1;i*i<=n;++i){
    	if(i%n==0){
    		A.push_back(i);
    		if(i*i!=n){ // 对于 n 是完全平方数的情况 如果不加以判断会被记录两次
    			A.push_back(n/i);
    		}
    	}
    }
    
  • 求出 \([1,n]\) 所有正整数的所有约数

    可以直接将上面的东西跑 \(n\) 遍,总复杂度 \(O(n\sqrt n)\)

    复杂度不够优秀。考虑枚举 \(1\)\(n\) 的所有正整数 \(x\),将 \(x,2x,···\) 的约数集合中添加一个元素 \(x\)

    这样总复杂度降到了 \(O(n+\frac n2+\frac n3 ···· +1)=O(n \ln n)\)

    std::vector <int> A[MAXN];
    
    for(int i=1;i<=n;++i){
    	for(rr int j=1;i*j<=n;++j){
    		A[i*j].push_back(i);
    	}
    }
    

如果一个正整数只有 \(1\) 和它本身两个因子,那么我们称它为素数(或质数)。\(1\) 不是质数,\(2\) 是最小的质数。如果一个正整数的因子个数大于 \(2\),则我们称它为合数\(1\) 也不是合数。最小的合数是 \(4\)

算术基本定理

\(n\) 是正整数且 \(>1\)\(p_i\) 均为不同的素数,\(c_i >0\) 时,有唯一的 \(p\)\(c\) 使得

\[n=\prod_{i=1}^{m} p_i^{c_i} \]

其中 \(c_i\) 被称为 \(n\) 中素因子 \(p_i\)次数(指数),\(p_i\) 被称为 \(n\) 的素因子(质因子)。

证明:如果有两个分解式 \(n=\prod_{i=1}^{m} p_i^{c_i}\)\(n=\prod_{i=1}^{m} {p'}_i^{{c'}_i}\)。不妨重排序列,设 \(\min\{p_i\} = p_1\)\(\min\{{p'}_i\} = {p'}_1\)\(p_1 \mid n \Rightarrow p_1 \mid \prod_{i=1}^{m} {p'}_i^{{c'}_i}\),则必定存在一个 \({p'}_i\) 使得 \(p_1 \mid {p'}_i\)。同理,存在 \(p_j\) 使得 \({p'}_1 \mid p_j\)。因为 \({p'}_i,p_j\) 均为素数,所以可以改写为 \({p'}_i = p_1,p_j = {p'}_1\)

观察到 \(p_1,{p'}_1\) 均为序列中最小的数,因此 \(p_1 = {p'}_1\)。将这两项移除,可以递归地证明。

  • 推论
    \(n\) 的正约数个数为

    \[\prod_{i=1}^{m} (c_i+1) \]

    证明:感性理解,\(n\) 的约数的唯一分解中每个质数的次数不可能超过 \(n\) 的唯一分解中该质数的次数。只要满足了这个限制,次数可以随便取,取 \(0\)(不选这个质因子)到 \(c_i\) 中的任何指数都可以,因此是 \(c_i + 1\) 种取法。根据乘法原理,把每个质数的选法乘起来。

\(n\) 的正约数和为

\[ \prod_{i=1}^{m} (\sum_{j=0}^{c_i} p_i^{j}) \]

证明:和上面差不多,不再赘述。

常用性质

  • 性质 \(1\)

    \[d \mid a ,d \mid b \Rightarrow d \mid ax + by (x,y \in \mathbb{Z}) \]

    证明:显然。值得一提的是,\(ax + by\) 被称为 \(a,b\)线性组合

  • 引理 \(1\)

    \(d | a\) 的充分必要条件是 \(d\) 中任意一素因子的指数不超过 \(a\) 中该素因子的次数。

    这是显然的,不需要给出证明。

  • 引理 \(1\) 的推论

    \(\text{lcm} (a,b) \times \gcd(a,b)= a \times b\)

    证明:令 \(a,b\) 的唯一分解分别为 \(a = \prod \limits_{i=1}^{m} p_i^{c_i},b = \prod \limits_{i=1}^{m} p_i ^{d_i}\),此时对于每个 \(i\)\(c_i,d_i\) 不能同时为 \(0\)。由引理 \(1\) 可知,\(\text{lcm}(a,b),\gcd(a,b)\) 的唯一分解分别为 \(\text{lcm}(a,b) = \prod \limits_{i=1}^{m} p_i ^{\max(c_i,d_i)},\gcd(a,b) = \prod\limits_{i=1}^{m} p_i^{\min(c_i,d_i)}\)

    显然对于任意整数 \(a,b\),有 \(\max(a,b) + \min(a,b) = a+b\),因此 \(\text{lcm}(a,b) \times \gcd(a,b) = \prod\limits_{i=1}^{m} p_i ^{\max(c_i,d_i) + \min(c_i,d_i)} = \prod\limits_{i=1}^{m} p_i ^{c_i + d_i} = a \times b\)

  • 性质 \(2\)

    \[d \mid a,d \mid b \Leftrightarrow d \mid \gcd(a,b) \]

    其中 \(\gcd(a,b)\)\(a,b\) 的最大公约数。

    证明:右推左很显然。因为 \(d \mid \gcd(a,b)\),又 \(a,b\) 均为 \(\gcd(a,b)\) 的倍数,因此 \(d\) 也整除 \(a,b\)

    由引理 \(1\) 及其推论,设 \(d = \prod \limits_{i=1}^{m} p_i^{e_i}\)\(d \mid a\)\(\forall i,e_i \leq c_i\)\(\forall\) 是「对于任意」符号,\(c_i\)\(a\) 的唯一分解中各个素因子的次数。

    同理可推得 \(\forall i,e_i \leq d_i\),其中 \(d_i\)\(b\) 的唯一分解中各个素因子的次数。

    两式联立,得 \(\forall i,e_i \leq \min(c_i,d_i)\),即 \(d \mid \gcd(a,b)\)

  • 性质 \(3\)

    \[\gcd(a,b) = \gcd(b,a \mod b) \]

    证明:考虑证明一个更强的条件,即 \(\gcd(a,b)\)\(\gcd(b, a\mod b)\) 的约数集合相同。

    \(a = kb + r(0 \leq r < b)\)

    • 左推右:\(d \mid a,d \mid b \Rightarrow d \mid r\)

      由性质 \(2\),上面的条件和 \(d \mid \gcd(a,b) \Rightarrow d \mid r\) 等价。\(r = a - kb\),由性质 \(1\) 可知 \(r\)\(a,b\) 的一个线性组合,由已知得 \(d \mid a,d \mid b\),则 \(d \mid r\) 显然成立。

    • 右推左:\(d \mid r ,d \mid b \Rightarrow d \mid a\)

      \(a = kb + r\),即 \(r\)\(b\) 的一个线性组合。剩下的部分和上面类似,不再证明。

  • 欧几里得算法求 GCD

    inline int gcd(int a,int b){
    	if(b==0)
    		return a;
    	return gcd(b,a%b);
    }
    

    不断利用性质 \(3\),直到 \(b=0\),这个时候返回 \(a\),即上一层时的 \(b\) 即可(因为上一层的 \(b\) 造成了 \(a \mod b = 0\))。

posted @ 2021-02-04 17:11  Meatherm  阅读(213)  评论(0编辑  收藏  举报