数论初步
1. 欧几里得定理和唯一分解定理
A.欧几里得定理(即辗转相除法求最大公约数,Euclid algorithm)
算法:gcd(); 恒等式:gcd(a, b) = gcd( b, a %b) ,边界条件 gcd( a, 0) = a
原理分析: 123456 和 7890 的最大公因数是 6,这可由下列步骤(其中,“a mod b”是指取 a ÷ b 的余数)看出:
a | b | a mod b |
123456 | 7890 | 5106 |
7890 | 5106 | 2784 |
5106 | 2784 | 2322 |
2784 | 2322 | 462 |
2322 | 462 | 12 |
462 | 12 | 6 |
12 | 6 | 0 |
函数体:
int gcd (int a, int b){
return b==0 ? a : gcd(b, a%b);
}
B.唯一分解定理(求最小公倍数)
函数:lcm(a,b)
设
则
不难验证,,故
注意: 先除后乘,先乘后除(即 )中 a*b 这一步可能会溢出。
2. Eratosthenes筛法
A. 构造1~n 的素数表。
思想:对于不超过n 的每个非负整数p,删除2p,3p,4p,...,当处理完所有数后,还没有被删除的数就是素数。如果用vis[i]表示i是否被删除,筛选的代码如下:
memset(vis,0,sizeof(vis));
for(int i = 2; i <= n; i++)
for(int j = i*2; j <= n; j += i)
vis[j] = 1;
时间复杂度0(nlogn),允许在很短的时间内得到以内的所有素数。
改进
int m = sqrt(n + 0.5);
memset(vis,0,sizeof(vis));
for(int i = 2; i <= m; i++)
{
if(!vis(i)
{
for(int j = i*i; j <= n; j += i)
vis[j] = 1;
}
}
B. 素数定理
不超过n的正整数中,素数的个数: ,即和
比较接近,
25 | 168 | 1229 | 9592 | 78498 | 664579 | 5761455 | |
![]() | 22 | 145 | 1086 | 8686 | 72382 | 620421 | 5428681 |
注意:
质数(prime number)又称素数,有无限个。
质数定义为在大于1的自然数中,除了1和它本身以外不再有其他因数。附部分素数表如下:
3. 扩展欧几里得算法
算法描述:找出一对整数(x, y),使得 ax + by = gcd(a,b)。其中x, y可以是正数、负数或者0。例如:gcd(6,15) = 3, 6 * 3 + 15 *(-1) = 3,其中 x = 3, y = -1,这个方程的解可能不唯一。相应代码如下:
void gcd (int a, int b, int &d, int x, int y)
{
if(!b)
{
d = a; x = 1; y = 0;//边界
}
else
{
gcd(b, a%b, d, y, x);
y -= x*(a/b);
}
}
4. 同余与模算数
A. 基础: a mod b 表示a 除以 b 的余数, C语言表达式 a % b 。(b 为正整数,b<0时表达式也合法,但为防止b = 0,此处设b > 0)
则:
注意: a mod n 可能小于 b mod n ,需要相减后加上n
注意: a mod n 和 b mod n 相乘后可能超过int 的范围,需要用long long 保存中间结果。
公式三代码:
int mul_mod (int a, int b, int n)
{
a %= n; b %= n;
return (int)((long long) a * b % n);
}
B. 大整数取模
输入正整数n和m,输出 n mod m 的值。 ,
。
scanf("%s%d",n,&m);
int len = strlen(n);
int ans = 0;
for(int i = 0; i < len; i++)
ans = (int)(( (long long) ans*10 + n[i] - '0')%m);
printf("%d\n", ans);
C. 幂取模
输入正整数 a、n和m,输出的值。
int pow_mod(int a, int n, int m){
int ans = 1;
for(int i = 0; i < n; i++)
ans = (int)((long long)ans * a % m);
}
该算法的时间复杂度为O(n),当n很大时,速度慢 ,利用分治法改进:
int pow_mod(int a, int n, int m){
if(n == 0) return 1;
int x = pow_mod(a, n/2, m);
long long ans = (long long) x * x % m;
if(n%2 == 1) ans = ans * a % m;
return (int)ans;
}
D. 模线性方程组
记号表示同余,
含义是“a和b关于模n同余”,即
,等价于 a - b 是 n 的整数倍。 输入正整数 a、 b、n,解方程
。
。设倍数为y,即求解方程
解集是一个同余等价类。
计数与概率基础
1. 杨辉三角与二项式定理
A. 基础
1)加法原理:做一件事情有n个办法,每个办法有种方案,则一共有
种方案。 2)乘法原理:做一件事情有n个步骤,第i个步骤有
种方案,则一共有
种方案。 3)容斥原理:当方案归属间之间有交叉时,方案数为
, 且并集前的符号规律为:奇数个集合符号为正,偶数个集合符号为负。 4)有重复元素的全排列:有k个元素,其中第i个元素有
个,求全排列个数。 分析: 令所有ni之和为n,设所求全排列个数为x,首先做全排列,然后把所有元素编号。其中第s中元素编号为1~ns,由于编号后所有元素均不相同,方案总数为n的全排列数n!,即 n1!n2!n3!...nk!x=n!,再移项,即
5)可重复选择的组合:有n个不同元素,每个元素可以选多次,一共选k个元素,有多少种方法?例如,n = 3 ,k = 2时有6种: (1,1)、(1,2)、(1,3)、(2,2)、(2,3)、(3,3)。 分析: 设第i个元素选
个,则问题转化为求方程
的非负整数解的个数。 令
,则问题转化为求方程
的正整数解的个数。 想象
个“1”排成一排,则问题等价为:把这些“1”分成
个部分,有多少种分法? 相当于在
个“候选分割线”中选
个,即
B. 杨辉三角
C. 二项式定理
把展开,将得到一个关于
的多项式:
系数刚好和杨辉三角形一致,一般的,有二项式定理:
递推公式:
,
D. 输出杨辉三角形
//方法一,时间复杂度o(n^2)
memset(C,0,sizeof(C));
for(int i = 0; i <= n; i++)
{
C[i][0] = 1;
for(int j = 0; j <= i; j++)
C[i][j] = C[i-1][j-1] + C[i-1][j];
}
//方法二:递推公式
memset(C,0,sizeof(C));
for(int i = 0; i <= n; i++)
{
C[i] = 1;
for(int j = 0; j <= i; j++)
C[i] = C[i-1] * (n-i+1)/i;
}
2. 数论中的计数问题
A. 约数的个数。 给出正整数n的唯一分解式 ,求n个正约数的个数。 n的任意正约数也只能包含
,
,
等因子,不会有新的素因子出现。 对于n的某个素因子
,它在所求约数的指数可以是0,1,2,...,
共
种情况。 而且不同的素因子之间相互独立,根据乘法原理,n的正约数个数为:
B. 小于n且与n互素的整数的个数。 给出正整数n个唯一分解式,求1,2,3,...,n中与n互素的数的个数。
C. 1~n中所有数的欧拉phi函数值。
3. 编码与解码
待续。。。
4. 离散概率初步
A.条件概率 事件B发生的前提下,事假A发生的概率。 贝叶斯公式:
B.全概率公式 样本空间S分成若干个不想交的部分,,
,
,
,则:
待续。。。
其他
1. 递推
2. 数学期望
3. 连续概率