食用这篇文章前建议有素数相关的知识,若不了解的可以点开链接快速学习 数论 – 质数判定及其筛法求解
基本概念
-
设 a 和 b 是两个整数,如果 d | a 且 d | b,则称 d 为 a 与 b 的 公约数 \color{Orange}公约数 公约数。
-
除 0 之外 ,任何整数只有有限个因子。因而两个不全为 0 的整数只有有限个公因子,其中最大的称作 最大公约数 \color{Orange}最大公约数 最大公约数
试除法求约数
- 给定一个数 N ,求 [1 ,N ]的所有约数
注意 \color{yellow}注意 注意
n 为完全平方数的时候 s q r t ( n ) ∣ n ,但此时 s q r t ( n ) 和 n / s q r t ( n ) 只能算作一个约数,因为他俩相等。此算法时间复杂度为固定值 O ( √ n ) n为完全平方数的时候sqrt(n) | n,但此时sqrt(n)和n / sqrt(n)只能算作一个约数,因为他俩相等。此算法时间复杂度为固定值O(√n) n为完全平方数的时候sqrt(n)∣n,但此时sqrt(n)和n/sqrt(n)只能算作一个约数,因为他俩相等。此算法时间复杂度为固定值O(√n)
代码模板
vector<int> get_dividors(int x)
{
vector<int> res;
for(int i = 1; i <= x/i; i ++ )
if(x % i == 0)
{
res.push_back(i);
if(i != x / i) res.push_back(x / i); // 完全平方数只需要记 一个因子
}
sort(res.begin(), res.end()); // 排序
}
约数个数
算术基本定理 \color{Green}算术基本定理 算术基本定理
任何一个大于 1 的自然数 N, 如果 N 不为 质数,那么 N 可以 唯一分解成有限个质数的乘积
设 a > 1 ,则
a = p 1 α 1 ∗ p 2 α 2 ∗ ⋅ ⋅ ⋅ p k α k a = p_1^{α_1}*p_2^{α_2}*···p_k^{α_k} a=p1α1∗p2α2∗⋅⋅⋅pkαk
其中 p 1 , p 2 , ⋅ ⋅ ⋅ ⋅ , p k p_1,\ p_2,\ ····,\ p_k p1, p2, ⋅⋅⋅⋅, pk是不同的素数
α 1 , α 2 , ⋅ ⋅ ⋅ ⋅ , α k α_1,\ α_2,\ ····,\ α_k α1, α2, ⋅⋅⋅⋅, αk是正整数
并且在不记顺序的情况下,该表示是唯一的
约数个数定理 \color{SpringGreen}约数个数定理 约数个数定理
对于 N分解质因数 :
N = p 1 α 1 ∗ p 2 α 2 ∗ ⋅ ⋅ ⋅ p k α k N = p_1^{α_1}*p_2^{α_2}*···p_k^{α_k} N=p1α1∗p2α2∗⋅⋅⋅pkαk
由 约数定义 可知 ,对于 $ p_1^{α_1}$ 来说 ,它的约数 为
p 1 0 , p 1 1 ⋅ ⋅ ⋅ p 1 α 1 p_1^{0}, p_1^{1}···p_1^{α_1} p10,p11⋅⋅⋅p1α1
共 ( α 1 + 1 ) (\alpha_1 + 1) (α1+1)个同理 对于 N 其他的质因数来说 ,它们的约数 为 . . . ( α n + 1 ) ...(\alpha_n + 1) ...(αn+1) 个
故根据乘法原理可知:
N 的约数的个数为 ( α 1 + 1 ) ( α 2 + 1 ) ⋅ ⋅ ⋅ ( α n + 1 ) N 的 约数的个数为\ (\alpha_1 + 1)(\alpha_2 + 1)···(\alpha_n + 1) N的约数的个数为 (α1+1)(α2+1)⋅⋅⋅(αn+1)
代码模板
LL res ;
const long long mod = // 很大的一个数,用来保证答案在此范围
void get_primes(int x)
{
for(int i = 2; i <= x/i ; i ++ )
if(x % i == 0)
{
int s = 0;
while(x % i == 0) s ++, x /= i; // 计算 质因子 的个数 即 某个 α
res *= (LL) (s + 1) % mod; // N 的 约数的个数为 (α1 + 1)(α2 + 1)···(αn + 1)
}
if(x > 1) res *= (LL) (1 + 1) % mod;// x 若 最后为 大于 1 的质数,约数的个数为 1
}
约数之和
约数和定理 \color{SpringGreen}约数和定理 约数和定理
对于 N 分解质因数 :
N = p 1 α 1 ∗ p 2 α 2 ∗ ⋅ ⋅ ⋅ p k α k N = p_1^{α_1}*p_2^{α_2}*···p_k^{α_k} N=p1α1∗p2α2∗⋅⋅⋅pkαk
由约数个数定理可知 N 的 正约数个数有
( α 1 + 1 ) ( α 2 + 1 ) ⋅ ⋅ ⋅ ( α n + 1 ) \ (\alpha_1 + 1)(\alpha_2 + 1)···(\alpha_n + 1) (α1+1)(α2+1)⋅⋅⋅(αn+1)
那么 N 的 d(n)个正约数的和为
δ ( n ) = ( p 1 0 + p 2 1 + ⋅ ⋅ ⋅ p 1 α 1 ) ∗ ⋅ ⋅ ⋅ ∗ ( p n 0 + p n 1 + ⋅ ⋅ ⋅ p n α n ) δ(n) = (p_1^0 + p_2^1+···p_1^{\alpha1})*···*(p_n^0 + p_n^1+···p_n^{\alpha_n}) δ(n)=(p10+p21+⋅⋅⋅p1α1)∗⋅⋅⋅∗(pn0+pn1+⋅⋅⋅pnαn)
秦九韶算法 \color{Green}秦九韶算法 秦九韶算法
计算一元n次多项式:
f ( x ) = a n x n + a n − 1 x n − 1 + a n − 2 x n − 2 + . . . a 1 x 1 + c = ( . . . ( a n x + a n − 1 x + a n − 2 ) x . . . + a 1 ) x + c f(x)= a_nx^n + a_{n-1}x^{n-1} + a_{n-2}x^{n-2} +... a_{1}x^{1}+ c\\\ \ \ \ \ \ =(...(a_nx + a_{n-1}x+ a_{n-2})x...+ a_1)x + c f(x)=anxn+an−1xn−1+an−2xn−2+...a1x1+c =(...(anx+an−1x+an−2)x...+a1)x+c
秦九韶算法实现
秦九韶算法的实现只是一个模拟算法的过程。假设 a [ i ] a[ i ] a[i] 数组输入了从多项式在次数为$\ i\ $那项的系数,那么秦九韶算法的核心代码块就是:
LL a[i];
void qjs()
{
for(int i = n - 1; i >= 1; i -- )
ans *= x, ans += a[i]; // 也可以写成 ans =(ans * x + a[i])
}
代码模板
LL get_sum(int a, int b) // a 为 p , b 为各种 α
{
LL t = 1 ;
while(b --)
{
t = (t * a + 1) % mod;// 这里 x 为 p , a【i】 恒为 1
}
}