声明
截取oy同学的博客:https://www.luogu.org/blog/ollie906086458/post-1-post
之后再自己整理
六、CRT/EXCRT
1.CRT
转载某大佬(%%%),蒟蒻修改部分
1.定义:
若m[1],m[2],...,m[n] 是两两互质的正整数, (M= prod_{i=1}^n{m[i]}),(M[i]=M/m[i] ,t[i]) 是线性同余方程 (M[i] * t[i] ≡1(mod m[i]))的一个解。对于任意的(n)个整数(a[1], a[2], a[3], ... , a[n]),则同余方程组为:
有整数解,方程组的解为
并且在%M意义下有唯一解。
2.证明:
因为(M[i] = M/m[i]) 是除(m[i]) 之外所有模数的倍数,所以 (∀) (任意)(k eq i),(a[i]M[i]t[i]≡0(mod m[k])).又因为 (a[i]M[i]t[i] ≡a[i] (mod m[i])),所以代入(x)得
3.结论:
中国剩余定理给出了模数两两互质的线性同余方程组的一个特殊解。方程组的通解可以表示为(x+kM(k∈Z))。有些题目要求我们求出最小的非负整数解,只需把x对M取模,并让x落在0~M-1的范围内即可。
int intchina(int r)
{
int Mi,x,y,d,ans=0;
int M=1;//注意取1
for(int i=1;i<=r;i++) M*=m[i];
for(int i=1;i<=r;i++){
Mi=M/m[i];
exgcd(Mi,m[i],d,x,y);
ans=(ans+Mi*x*a[i])%M; //Mi相当于Mi,x—>ti
}
return (ans+M)%M;//防负数
}
2.EXCRT
某位神仙说提高不会考,如果考到我认命,如果实在想学可以点击这里
七、线性代数
0.前置
线性代数比较难(矩阵)而且不咋考,所以就马马虎虎地走个过场
1.快速幂
这个大家都会,我就只贴板子了
如果你实在要搞懂原理 戳我
求:
code:
ll quick_pow(ll a, ll b, ll p)//a^b mod p
{
ll t=1;
while(b)
{
if(b&1) t=t*a%p;
a=a*a%p;
b>>=1;
}
return t;
}
2.矩阵相关
%%%大佬 可爱即是正义
直接使用传送术(懒得排了,也不是很重要的东西)
3.*高斯消元
某位神级清华sang师说高斯消元noip不会考,不属于提高组,所以不讲,如果感兴趣自己下去查吧。
八、组合数学
前置:这个也是考的比较多的
1.卡特兰数(卡姿兰数)
说明:原博客
1.卡特兰数是啥:
卡特兰数是一种经典的组合数,经常出现在各种计算中,其前几项为 : 1, 2, 5, 14, 42, 132, 429, 1430, 4862, 16796, 58786, 208012, 742900, 2674440, 9694845, 35357670, 129644790, 477638700, 1767263190, 6564120420, 24466267020, 91482563640, 343059613650, 1289904147324, 4861946401452, ...
TIP:Cn,hn,fn均表示卡特兰数(在这)
2.卡特兰数的公式
① 递归公式1
如果我们用这个公式显然我们要使用递归算法,那么数据一大就在时空上很麻烦
② 递归公式2
这个公式应用递推,看上起十分和善
但对大数据呢?
我们注意到大数据的时候 f(n) 会很大,这时候题目一般会让你对某素数取模(当然你可以打高精度)
但你在取模过程中难保一个 f(n)%mod=0
那么根据公式下面所有的数都会等于0,于是你就愉快的WA了
③ 组合公式1
卡特兰数可以与组合数联系起来,得到上面的公式
而组合数就是一个杨辉三角,可以递推得到
但我们发现对于大数据你要取模,而对于除法你是没办法用膜的性质的(当然你可以应用逆元),所以造成了麻烦
④ 组合公式2
与组合数公式1不同这个是两个组合数的减法
减法是可以用膜的性质的,于是你可以愉快的AC了。
3.卡特兰数的应用
①、进出栈问题:
栈是一种先进后出(FILO,First In Last Out)的数据结构.如下图1,2,3,4顺序进栈,那么一种可能的进出栈顺序是:1In→2In→2Out→3In→4In→4Out→3Out→1Out, 于是出栈序列为1,3,4,2。
那么一个足够大的栈的进栈序列为1,2,3,⋯,n时有多少个不同的出栈序列?
我们可以这样想,假设 x 是最后一个出栈的数。
由于x是最后一个出栈的,所以可以将已经出栈的数分成两部分
1.比 x 小
2.比 x 大
比x小的数有x-1个,所以这些数的全部出栈方案数为f[x-1]
比x大的数有n-x个,所以这些数的全部出栈方案数为f[n-x]
所以一共有 (f[x-1]*f[n-x]) 种方案。显而易见,(x) 取不同值时,产生的出栈序列是相互独立的,所以结果可以累加。(x)的取值范围为 (1) 至 $ n$,所以结果就为
(f[n] = f[0] * f[n-1] + f[1] * f[n-2] + ... + f[n-1] * f[0])
②. 二叉树构成问题
有n个结点,问总共能构成几种不同的二叉树?
(1)先考虑只有一个节点的情形,设此时的形态有 (f[1]) 种,那么很明显 (f[1]=1)
(2)如果有两个节点呢?我们很自然想到,应该在 (f[1]) 的基础上考虑递推关系。 那么,如果固定一个节点后,左右子树的分布情况为(1=1+0=0+1),故有(f[2] = f[1] + f[1])
(3)如果有三个节点,我们需要考虑固定两个节点的情况么?(当然不,因为当节点数量大于等于(2)时,无论你如何固定,其形态必然有多种 我们考虑固定一个节点,即根节点)。好的,按照这个思路,还剩2个节点,那么左右子树的分布情况为(2=2+0=1+1=0+2)。 所以有(3)个节点时,递归形式为 (f[3]=f[2]+f[1]*f[1]+f[2])。(注意这里的乘法,因为左右子树一起组成整棵树,根据排列组合里面的乘法原理即可得出)
(4)那么有n个节点呢?我们固定一个节点,那么左右子树的分布情况为
(n-1=n-1 + 0 = n-2 + 1 = … = 1 + n-2 = 0 + n-1)。此时递归表达式为(f[n] = f[n-1] + f[n-2]f[1] + f[n-3]f[2] + … + f[1]f[n-2] + f[n-1])
即给定(N)个结点,能构成(h(N))种不同的二叉树。(h(N))为卡特兰数的第(N)项。(二叉树性质)
③、凸多边形的三角形划分
一个凸的(n)边形,用直线连接他的两个顶点使之分成多个三角形,每条直线不能相交,问一共有多少种划分方案。
这也是非常经典的一道题。我们可以这样来看,选择一个基边,显然这是多边形划分完之后某个三角形的一条边。图中我们假设基边是(p1-pn),我们就可以用(p1,pn)和另外一个点假设为(pi)做一个三角形,并将多边形分成三部分,除了中间的三角形之外,一边是(i)边形,另一边是(n-i+1)边形。(i)的取值范围是(2)到(n-1)。所以本题的解(c(n)=c(2)c(n-1)+c(3)c(n-2)+...c(n-1)c(2))。令(t(i)=c(i+2))。则(t(i)=t(0)t(i-1)+t(1)t(i-2)...+t(i-1)t(0))。很明显,这就是一个卡特兰数了。
④、求n+1个叶子的满二叉树的个数
不证,知道就行
⑤、路径问题
在n*n的格子中,只在下三角行走,每次横或竖走一格,有多少中走法?
其实向右走相当于进栈,向左走相当于出栈,本质就是n个数出栈次序的问题,所以答案就是卡特兰数。(利用这个模型,我们解决这个卡特兰问题的变形问题,并顺便给进出栈问题的解法一个几何解释)
⑥、划分问题
将一个凸n+2边形区域分成三角形区域的方法数?
证明都差不多啦,自己研究去吧
⑦、握手问题
2n 个人均匀坐在一个圆桌边上,某个时刻所有人同时与另一个人握手,要求手之间不能交叉,求共有多少种握手方法
4、引理
这就不说了,没啥对考试太实用的,如果实在想看就往上翻,去原博客看,考试知道这些就行了
5、code
说了一堆终于到终点了哈
代码来自 xiejinhao (%%%)
①公式1:
#include<cstdio>
#define MAX_N 20//这你自己看要定义多大吧
#define ll long long
using namespace std;
int n;
ll f[MAX_N];
int main()
{
f[0]=f[1]=1;
scanf("%d",&n);
for(int i=2;i<=n;i++)
{
for(int j=0;j<i;j++)
{
f[i]+=f[j]*f[i-j-1];
}
}
printf("%lld",f[n]);
return 0;
}
②公式2:
#include<cstdio>
#define MAX_N 20
#define ll long long
using namespace std;
int n;
ll f[MAX_N];
int main()
{
f[0]=f[1]=1;
scanf("%d",&n);
for(int i=2;i<=n;i++)
{
f[i]+=f[i-1]*(4*i-2)/(i+1);
}
printf("%lld",f[n]);
return 0;
}
③公式3:
#include<cstdio>
#define MAX_N 20
#define ll long long
using namespace std;
int n;
ll c[MAX_N*2][MAX_N];
int main(){
scanf("%d",&n);
for(int i=1;i<=2*n;i++)
{
c[i][0]=c[i][i]=1;
for(int j=1;j<i;j++)
{
c[i][j]=c[i-1][j]+c[i-1][j-1];
}
}
printf("%lld",c[2*n][n]/(n+1));
return 0;
}
④公式4:
#include<cstdio>
#define MAX_N 20
#define ll long long
using namespace std;
int n;
ll c[MAX_N*2][MAX_N];
int main(){
scanf("%d",&n);
for(int i=1;i<=2*n;i++)
{
c[i][0]=c[i][i]=1;
for(int j=1;j<i;j++)
{
c[i][j]=c[i-1][j]+c[i-1][j-1];
}
}
printf("%lld",c[2*n][n]-c[2*n][n-1]);
return 0;
}
不懂看公式去
卡姿兰数完结
2、排列组合
1、计数原理:
如果 A 地到 B 地有三条路径,B 地到 C 地有两条路径,那么A 到 C 共有 2 * 3 = 6 种方案
如果 A 还有一种直接到 C 的方案,那么就一共有 7 种方案
上面就是加法原理和乘法原理(不知道自行百度,好像不知道也无所谓哦)
2、排列和组合:
从 n 个元素中取出 m 个元素,排成一排,叫做从 n 个元素中取出 m 个元素的一个排列
从 n 个元素中取出 m 个元素的所有组合(不管其顺序)的个数,叫做 n 个元素中取出 m 个元素的组合数
这东西太多了,我们讲几个基础的
可以理解为:将原本的每个组合都反转,把原来没选的选上,原来选了的去掉,这样就变成从n个元素种取出n−m个元素,显然方案数是相等的。
可理解为:含特定元素的组合有(C^{m-1}_{n-1}),不含特定元素的排列为(C^{m}_{n-1})
组合数求和公式:
自己记去
3、二项式定理
可以将x+y的任意次幂展开成和的形式
其中每个(inom{n}{k})为一个称作二项式系数的特定正整数,其等于(frac{n!}{k!(n-k)!})。这个公式也称二项式公式或二项恒等式。使用求和符号,可以把它写作
4、杨辉三角
来自古人的神秘力量
大佬博客的搬运工——ollie
杨辉三角可以帮助你更好地理解和记忆组合数的性质:
- 第(n)行的(m)个数可表示为 (C^{m-1}_{n-1}),即为从(n-1)个不同元素中取(m-1)个元素的组合数。
- 第(n)行的数字有(n)项。
- 每行数字左右对称(第(n)行的第(m)个数和第(n-m+1)个数相等,(C_{n}^{m}=C_{n}^{n-m}),由(1)开始逐渐变大。
- 每个数等于它上方两数之和(第(n+1)行的第(i)个数等于第(n)行的第(i-1)个数和第(i)个数之和,即(C_{n+1}^{i}=C^{i}_{n}+C_{n}^{i-1})。
- ((a+b)^{n})的展开式中的各项系数依次对应杨辉三角的第(n+1)行中的每一项(二项式定理)。
code:
c[1][1] = 1;
for(int i = 2; i <= n; i++)
for(int j = 1; j <= i; j++)
{
c[i][j] = c[i-1][j] + c[i-1][j-1];
}
九、数学期望
所有的权值乘以它对应的概率
通俗一点就是设(X[i])为(i)的权值,(P[i])是(i)对应出现的概率,期望值为(f),有:
完结撒花
还有部分内容未补上,后期补充上去