PART0 OI Wiki
引用自官网:
OI Wiki 致力于成为一个免费开放且持续更新的知识整合站点,大家可以在这里获取关于 编程竞赛 (competitive programming) 有趣又实用的知识,我们为大家准备了竞赛中的基础知识、常见题型、解题思路以及常用工具等内容,帮助大家更快速深入地学习编程竞赛。
PART1 简介
在 OI/ACM 的各种比赛中,常常会有数学题的出现。
这些数学题以数论、排列组合、概率期望、多项式为代表,可以出现在几乎任何类别的题目中。
举几个栗子:
- 多项式可以优化卷积形式的背包,可以做一些字符串题。
- 很多 DP 类型的题都可以结合排列组合/概率期望。
NOIP 中有可能会考察的知识点
然而 NOIP 可能考察更多的知识点,这里只是利用之前的题总结出来的,考过或者考的概率比较大的知识点。
NOIP 对数学的考察还处在一个比较简单的范围。
- 进制相关——通常是利用进制优化一些问题
- 位运算——状压常用
- 高精度——不包括需要利用多项式的高精度
- 整除性质——\(gcd\),欧拉函数,费马小定理
- 同余相关——\(exgcd\),逆元,中国剩余定理
- 概率期望——概率 DP,以及有可能用到高斯消元解决的概率 DP
- 排列组合——杨辉三角,二项式定理,卢卡斯定理,卡特兰数
PART2 最大公约数
最大公约数即为 Greatest Common Divisor,常缩写为 gcd
在素数一节中,我们已经介绍了约数的概念。
一组数的公约数,是指同时是这组数中每一个数的约数的数。而最大公约数,则是指所有公约数里面最大的一个。
那么如何求最大公约数呢?我们先考虑两个数的情况。
两个数的
如果我们已知两个数 \(a\) 和 \(b\) ,如何求出二者的最大公约数呢?
不妨设 \(a > b\)
我们发现如果 \(b\) 是 \(a\) 的约数,那么 \(b\) 就是二者的最大公约数。
下面讨论不能整除的情况,即 \(a = b \times q + r\) ,其中 \(r < b\) 。
我们通过证明可以得到 \(\gcd(a,b)=\gcd(b,a \bmod b)\) ,过程如下:
设 \(a=bk+c\) ,显然有 \(c=a \bmod b\) 。设 \(d|a\ \ \ d|b\) ,则 \(c=a-bk\) \(\frac{c}{d}=\frac{a}{d}-\frac{b}{d}k\) 由右边的式子可知 \(\frac{c}{d}\) 为整数,即 \(d|c\) 所以对于 \(a,b\) 的公约数,它也会是 \(a \bmod b\) 的公约数。
反过来也需要证明
设 \(d|b\ \ \ d|(a \bmod b)\) ,我们还是可以像之前一样得到以下式子 \(\frac{a\bmod b}{d}=\frac{a}{d}-\frac{b}{d}k\) \(\frac{a\bmod b}{d}+\frac{b}{d}k=\frac{a}{d}\) 因为左边式子显然为整数,所以 \(\frac{a}{d}\) 也为整数,即 \(d|a\) ,所以 \(b,a\bmod b\) 的公约数也是 \(a,b\) 的公约数。
既然两式公约数都是相同的,那么最大公约数也会相同
所以得到式子 \(\gcd(a,b)=\gcd(b,a\bmod b)\)
既然得到了 \(\gcd(a, b) = \gcd(b, r)\) ,这里两个数的大小是不会增大的,那么我们也就得到了关于两个数的最大公约数的一个递归求法。
int gcd(int a, int b) {
if (b == 0) return a;
return gcd(b, a % b);
}
递归至 b==0
(即上一步的 a%b==0
) 的情况再返回值即可。
如果两个数 \(a\) 和 \(b\) 满足 \(\gcd(a, b) = 1\) ,我们称 \(a\) 和 \(b\) 互质。
多个数的
那怎么求多个书的最大公约数呢?显然答案一定是每个数的约数,那么也一定是每相邻两个数的约数。我们采用归纳法,可以证明,每次取出两个数求出答案后再放回去,不会对所需要的答案造成影响。
PART3 EXGCD - 扩展欧几里得定理
目的:求 \(ax+by=\gcd(a,b)\) 的一组可行解
证明
设
\(ax_1+by_1=\gcd(a,b)\)
\(bx_2+(a\bmod b)y_2=\gcd(b,a\bmod b)\)
由欧几里得定理可知: \(\gcd(a,b)=\gcd(b,a\bmod b)\)
所以 \(ax_1+by_1=bx_2+(a\bmod b)y_2\)
又因为 \(a\bmod b=a-(\lfloor\frac{a}{b}\rfloor\times b)\)
所以 \(ax_1+by_1=bx_2+(a-(\lfloor\frac{a}{b}\rfloor\times b))y_2\)
\(ax_1+by_1=ay_2+bx_2-\lfloor\frac{a}{b}\rfloor\times by_2=ay_2+b(x_2-\lfloor\frac{a}{b}\rfloor y_2)\)
因为 \(a=a,b=b\) ,所以 \(x_1=y_2,y_1=x_2-\lfloor\frac{a}{b}\rfloor y_2\)
将 \(x_2,y_2\) 不断代入递归求解直至 GCD(最大公约数,下同)为 0
递归 x=1,y=0
回去求解。
int Exgcd(int a, int b, int &x, int &y) {
if (!b) {
x = 1;
y = 0;
return a;
}
int d = Exgcd(b, a % b, x, y);
int t = x;
x = y;
y = t - (a / b) * y;
return d;
}
函数返回的值为 GCD,在这个过程中计算 \(x,y\) 即可