第10章、11章内容概括(总结)+ 后面具体的行动
第10章与第11章与其他章节不同,对于即将参加csp的我来说,要选择考点进行学习,由于题目数量与难度比较大,所以迟迟没有更新,
但是这并不能再拖下去了,所以今天一定要写一写博客,并且为以后的规划做出明确的规定。
先说一说以后的规划吧!学完书,就需要复习书上的内容,打牢了才能继续前进,所以总结完所有的内容我会把之前的代码与博客还有书认认真真的看一遍,将不清楚的只是巩固,然后在学习新的内容,学习什么呢?蓝书(训练指南)我可能以后再进行学习,蓝书的内容很好,不过由于涉及到了其他的更加高深的问题,而距离比赛的时间不多了,所以就不能学习过多的内容,而是准备比赛,然后我略微看了一下算法竞赛训练指南这本书,里面有很多比赛需要的内容并且紫书没有的地方,于是决定通过这本书补补漏洞,然后基本上没有太多时间去做别的事情了,学习了紫书这么长的时间,确实有很多心得体会,最大的感受是让我写代码能写的更简单更加能够处理复杂的输入以及问题了(UVa上的题给了我很大的帮助啊!),这就需要我认认真真的吧学习的内容巩固了,没学习的内容同样有很多,有一部分比赛是需要考的,所以在复习完紫书时,这本算法竞赛进阶指南将帮助我去补遗漏的地方,期间模拟赛一定不会少的,这样多打模拟赛才能在真正比赛中取得更好的成绩,看了看日历,时间紧迫啊!同时通过洛谷上的打卡知道了我努力了这么多天,真正的成绩对我来说未必有这种经历重要,但是我一定会努力取得令自己满意的成绩的,我成长了,感谢在我学习期间一直帮助我的人,感谢紫书作者刘汝佳,感谢令我不断努力的信息竞赛。
长风破浪会有时,直挂云帆济沧海。
下面就是10、11章的内容了。
10 数论是算法、计算机的基础,所以拥有好的数学基础十分重要。
欧几里得算法:
int gcd(int a, int b) { return b == 0 ? a : gcd(b, a%b); }
这里的证明就不说了(其他博客上会有更加详细的介绍)。
上面的程序就是求出a、b的最大公约数。
对于两个数的最大公约数为gcd(a, b)以及最小公倍数lcm(a, b)则a*b = gcd(a, b)*lcm(a, b),这个比较好证明的,大家自行百度。
对于求素数,这里给出了Eratosthenes筛法
memset(vis, 0, sizeof(vis)); for (int i = 2; i <= n; ++i) for (int j = i*2; j <= n; j += i) vis[j] = 1;
其实我们写出更加优化的程序:
memset(vis, 0, sizeof(vis)); int m = sqrt(n + 0.5); for (int i = 2; i <= m; ++i) for (int j = i * i; j <= n; j += i) vis[j] = 1;
对于i来讲,vis[i] = 1说明不是素数,反之则是。
下面是扩展欧几里得算法,用于求一元二次方程:
void gcd(int a, int b, int& d, int& x, int& y) { if (b == 0) { d = a; x = 1; y = 0; } else { gcd(b, a%b, d, y, x); y -= x*(a/b); } }
这里证明略,我们得到了一组解,其实其他解为:g = gcd(a, b) b' = b/g a' = a/g (x + kb', y + ka')
下面就是模算数方面的规则了:
(a+b)modn = (amodn + bmodn) mod n (a-b)modn = (amodn - bmodn + n) mod n abmodn = (amodn)*(bmodn)modn
然后给出了幂取模的快速算法:
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) ans = ans * a % m; return (int) ans; }
模线性方程组:ax同余b(modn)
这里设ax-b=ny,变成了ax+ny=b这不就是二元一次方程组吗,这里仍然能够用exgcd进行求解,特别的是,当b=1时,ax同余1(modn)
的解称为a关于模n的逆,这里a与n必须互素,解法仍然是exgcd
下面是计数与概率基础。
加法原理:一个事情有n个方法,第i个方法有pi种方案,则一共有p1+p2+p3+...+pn种方案。
乘法原理:做一件事情有n个步骤,第i个步骤有pi种方案,一共有p1*p2*p3*...*pn种方案。
容斥原理:这里就不详细写出来了,建议大家参考书。
可重复元素的全排列:有k个元素,其中第i个元素有ni个,求全排列的个数:
将所有的元素看成不同的,一共有n!种方法,对于每一种有ni!个,所以总的个数x满足的等式为n1!n2!n3!...x = n!
可重复选择的组合:有n个不同元素,每个元素可以选多次,一共选k个元素,有多少种方法。
设第i个元素选择xi个,问题转化为x1+x2+...+xn=k的非负整数解的个数,令y=x+1
则答案为y1+y2+...+yn=k+n正整数解的个数,我们想象成k+n个1排成一排,利用插板法的原理,一共有C(k+n-1, n-1)种方法。
杨辉三角与二项式定理:
1
1 2 1
1 3 3 1
......
另一方面,把(a+n)^n次方展开,能够得到二项式定理(这里就不写出复杂的式子了)
给定n,如何求出(a+b)^n的所有项的系数呢?这里使用递推的方法:
memset(C, 0, sizeof(C)); for (int i = 0; i < n; ++i) { C[i][0] = 1; for (int j = 1; j <= i; ++j) C[i][j] = C[i-1][j] + C[i-1][j-1]; }
利用等式C(n,k) = (n - k + 1 / n) * C(n, k-1)
C[0] = 1; for (int i = 1; i <= n; ++i) C[i] = C[i-1] * (n - i + 1) / i;
数学中的计数问题:
约数的个数,给出n的唯一分解式,求出n的正约数的个数。
这个问题非常简单,由于式子太难写,就不写出来了。
小于n且与n互素的整数个数
用容斥原理。首先从总数中减去p1,p2,p3...pk倍数的个数,然后加上两个素因子的倍数,以此类推,我们会得到一个比较复杂的公式(百度吧,这么复杂的公式我写不出来orz),可以转化成如下的式子:x(n) = n(1-1/p1)(1-1/p2)(1-1/p3)...(1-1/pn)
下面是求n的欧拉函数:
int euler_phi(int n) { int m = sqrt(n + 0.5); int ans = n; for (int i = 2; i <= m; ++i) if (n % i) { ans = ans / i * (i - 1); while (n % i == 0) n /= i; } if (n > 0) ans = ans / n * (n - 1); return ans; }
以及求1-n所有数的欧拉phi值:
void phi_table(int n) { for (int i = 2; i <= n; ++i) phi[i] = 0; phi[1] = 1; for (int i = 2; i <= n; ++i) if (!phi[i]) for (int j = i; j <= n; j += i) { if (!phi[j]) phi[j] = j; phi[j] = phi[j] * i / (i - 1); } }
离散概率:
条件概率:P(A|B) = P(AB) / P(B)
全概率公式:将样本S分成若干个不相交的部分,则P(A) = P(A|B1) * P(B1) + P(A|B2) * P(B2) + ... + P(A|Bn) * P(Bn)
其他数学专题:
递推:汉诺塔问题:f(n) = 2f(n-1) + 1
Fibonacci数列:f(n) = f(n-1) + f(n-2)
Catalan数:f(n) = f(2)f(n-1) + f(3)f(n-2) + f(4)f(n-3) + ... + f(n-1)f(2)
上面的Catalan数可以转化成为f(n+1) = (4n - 6) / n * f(n)
上面的数学专题都需要具体情境的推到,建议去网上查询情境
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
11 图论(最小生成树、单源最短路)
这个部分明天在说吧,先写到这里。