数论
\(update: 2025/8/5\)
其实它不简单,但也不难
初等数学
方差
常规计算:
推导:
组合数学
直观且简单地说就是排列与取数问题
加法原理&乘法原理
加法原理: 做一件事有多类方式,等级相同(各部分相互间独立),则做这件事的方法数量为各类方式之和
乘法原理:做一件事有多步,各部分之间有先后顺序,则做这件事的方法数量为各类方式之积
排列
其一
\(n\)个不同的人,编号为\(1,2,3...n\),列队站成一行
每种列队的方法,都是长为\(n\)的一个排列
共有\(n!\)种方法
即选第一人时有\(n\)种
选第二人时有\(n-1\)种
......
根据乘法原理求得有\(n!\)种
其二
如果是从\(n\)个人里选出\(m\)个人,让他们站成一行;
这个问题的答案记作\(A^m_n\)
乘法原理得
组合
除法原理
从\(n\)个人中选出\(m\)个人,问多少种方法
这个问题的答案记作\(C^m_n\),但现在更常用\((^n_m)\)
乘法原理得\(A^m_n=(^n_m)*m!\)
因此
我们也可以将上面的论证称为"除法原理"
如果做一件事分为两步,共\(n\)种方法,完成第二步有\(n_2\)种方法
那么完成第一步有\(n/n_2\)种方法
圆排列
如果将上述问题转化为把\(n\)个人排成一环,并把旋转后相同的排法看成一种,求有多少种排法;
乘法原理:选出一号右边的人,再选出一号右边的右边的人...
除法原理:考虑\(n\)个人排成一行,选出\(n\)个人排成一个环,再选出一个人做第一行的第一个人
上述两种方法会得到相同的结果:\(n!/n=(n-1)!\)种
burnside引理(待补)
带队
现有三个老师,\(n\)个同学,每个老师带一些同学组成一队,假设每个老师分别带领\(n_A,n_B,n_C\)个人,求方案数
上面的问题答案记作
数学上,可以看成把\(n\)个元素放进三个不同的集合,每个集合大小给定,共有多少种分法
隔板法
考虑这样一个问题
求方程
的正整数解的个数
如果我们换个角度想,考虑这有\(n\)个小球,我们要将这些小球分成\(m\)组
于是我们将原问题转化为一个组合问题,易知它的方案和原题一一对应
那么我们再考虑将\(n\)个小球排成一行,那么有\(n-1\)个空隙,我们要选\(m-1\)个,插上一个隔板(这也许就是此方法名字的由来),则共有\((^{n-1}_{m-1})\)种方案
这种转化是很多看似与组合数学无关的问题的第一步解法 : 尝试将其转化为已知问题求解;(下面的二项式定理也是如此)
例题(待补)
二项式定理
考虑这样一个拆括号问题
这个好拆
怎么拆
由此引出二项式定理
考虑\((x+y)^n\)拆开写成\((x+y)*(x+y)*(x+y)*(x+y)\)...的形式
于是问题转化为对于每一个\((x+y)\),我们取左边还是取右边的组合问题
最终得到以下式子
状压DP(待补)
杨辉三角
真的很好用(前提你知道怎么用)
观察下面的三角形
\(1\)
\(1\) \(1\)
\(1\) \(2\) \(1\)
\(1\) \(3\) \(3\) \(1\)
\(1\) \(4\) \(6\) \(4\) \(1\)
\(1\) \(5\) \(10\) \(10\) \(5\) \(1\)
我们发现,每一个数都是上两个数的和(最左侧和最右侧的两列除外),因此我们得出杨辉三角的递推式
for(int i=1;i<=n;i++){
a[i][0]=a[i][i]=1;
for(int j=1;j<i;j++){
a[i][j]=a[i-1][j-1]+a[i-1][j];
}
}
多数情况下它只能作为一个优化用的方法,见luogu P2822
组合数性质
-
\[(^n_m)=(^{n-1}_{m-1})+(^{n-1}_m) \]
-
\[(^n_m)=\frac{n-m+1}{m}(^{n}_{m-1})=(^{n}_{n-m}) \]
可以用来计算杨辉三角的一行
-
\[\sum^n_{i=1}(^i_m)=(^{n+1}_{m+1}) \]
这里我们默认如果\(n<m\),那么\((^n_m)=0\)
这个性质是杨辉三角的按列求和,也称作"上指标求和"
-
\[\sum^n_{i=0}(^n_i)=2^n \]
-
\[\sum^k_{i=0}(^n_i)(^m_{k-i})=(^{n+m}_k) \]
组合意义证明
要证明代数的等式,我们可以构造一个组合问题
这个组合问题有两个视角.一个给出等式左边,一个给出等式右边
由于两边都计算了同一个问题的答案,左右相等
事实上,上面的所有性质都能通过此方法证明
组合数学杂项
等价类
等价关系
我们定义的,用以分辨等价的关系,
例如:项链的染色等价,是定义成旋转后相同的两个染色等价,也可以定义成,作任意次旋转或镜面对称后,两染色方案相同,则两方案等价
好的等价关系
一般满足以下三个条件
- 自反 : \(a\) ~ \(a\)
- 对称 : \(a\) ~ \(b\),则 \(b\) ~ \(a\)
- 传递 : \(a\) ~ \(b\) ,\(b\) ~ \(c\) ,则 \(a\) ~ \(c\)
事实上,只要一个等价关系满足上述三个条件,就是一个好等价关系,我们可以因此把集合分为多个等价类
\(a\)所在的等价类<\(a\)>={\(b|b\)~\(a\)}
通常我们会找一个代表元来区分不同等价类
例如:并查集
鸽笼原理(抽屉原理)
把&n&只鸽子放在\(m\)个笼子里,则至少有一个笼子放\(\lceil n/m \rceil\)只鸽子
原理极易理解,但如同杨辉三角一样,你需要知道何时使用它
初等数论
整除
如果\(a\)%\(b==0\),则称\(b\)整除\(a\),记作 \(b|a\)
一些显然的性质
- \(d|a,d|b\Rightarrow d|(a\pm b)\)
- \(b|a\Rightarrow bd|ad\)
- \(b|a,d|a,d|b\Rightarrow \frac{b}{d}|\frac{a}{d}\)
\(gcd\) & \(lcm\)
\(gcd\):最大公约数
\(lcm\):最小公倍数
显然
\(gcd(a,b)*lcm(a,b)=ab\)
gcd(欧几里得算法)
事实上,c++自带__gcd函数可以求gcd
\(gcd(a,b)=gcd(b,a \bmod b)\)
\(code\)
int gcd(int a,int b){
if(!b) return a;
return gcd(b,a%b);
}
exgcd(扩展欧几里得算法)
考虑这样一个问题
如何求\(ax+by=c\)的一组正整数解
\(exgcd\)给出了求\(ax+by=gcd(a,b)\)的方法
\(code\)
void exgcd(int a,int b,int &x,int &y){
if(!b) x=1,y=0;
else exgcd(b,a%b,y,x),y-=a/b*x;
}
使用时
int x,y
exgcd(a,b,x,y)
x=x*c/__gcd(a,b);
再来考虑如何让求的\(x\)最小
x=(x%b+b)%b;//因为要让x保证非负时尽可能小
例题
luogu P5656 【模板】二元一次不定方程 (exgcd)
\(code\)
//May all the beauty be blessed.
#include<bits/stdc++.h>
#define int long long
using namespace std;
int t;
int a,b,c;
void exgcd(int a,int b,int &x,int &y){
if(!b) x=1,y=0;
else exgcd(b,a%b,y,x),y-=a/b*x;
}
int gcd(int x,int y){
if(!y) return x;
else return gcd(y,x%y);
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
cin>>t;
while(t--){
int x,y;
cin>>a>>b>>c;
int d=gcd(a,b);
if(c%d){
cout<<-1<<'\n';
continue;
}
exgcd(a,b,x,y);
x=x*c/d,y=y*c/d;
int xl=b/d,yl=a/d;
int k=ceil((1.0-x)/xl);
x+=xl*k;
y-=yl*k;
if(y<=0){
int yy=y+yl*ceil((1.0-y)/yl);
cout<<x<<" "<<yy<<'\n';
}else cout<<(y-1)/yl+1<<" "<<x<<" "<<(y-1)%yl+1<<" "<<x+(y-1)/yl*xl<<" "<<y<<'\n';
}
}
逆元
在模的意义下,除法无法正常使用;
因此我们需要将除法改成乘法,以确保能正常取模
逆元存在条件
设求\(x\)的逆元,模\(p\)
当且仅当\(gcd(x,p)=1\)时存在逆元
证明(反证法):
设\(gcd(x,p)=d\),若\(d!=1\)
则对于\(x\equiv1 \pmod p\),有\(x-1\equiv0 \pmod p\)
又\(x=kd\),则不存在\(d|x-1\)
则不存在\(x-1 \equiv 0 \pmod p\)
证反毕
\(exgcd\)求法
条件:当\(gcd(x,p)=1\),即存在逆元时
void exgcd(int a,int b,int &x,int &y){
if(!b) x=1,y=0;
else exgcd(b,a%b,y,x),y-=a/b*x;
}
//用法
int x,y;
exgcd(a,mod,x,y);
x=(x%mod+mod)%mod;//防止出负
\(crt\) (中国剩余定理)
\(b_1,b_2,....b_n\)两两互质,
求解同余方程组
\(\begin{cases}
x\equiv a_1 (\bmod b_1)\\
x\equiv a_2 (\bmod b_2)\\
...\\
x\equiv a_n (\bmod b_n)
\end{cases}\)
想法:
先构造一个\(y_1\),使
\(\begin{cases}
y_1\equiv 1 (\bmod b_1)\\
y_1\equiv 0 (\bmod b_2)\\
...\\
y_1\equiv 0 (\bmod b_n)
\end{cases}\)
同理,求\(y_2,y_3,...,y_n\)
易知可通过\(exgcd\)求出\(x_i=y_i*a_i\),又由于$$\prod_{j=1,j!=i}^n b_j|y_i$$
得出$$y_i=\prod_{j=1,j!=i}^n b_j*k_i$$(其中\(k_i\)为一个系数),最终得如下式子
excrt(扩展中国剩余定理)
若上述\(b_1,...b_n\)不互质怎么办?
考虑合并方程
考虑\(n=2\) 时
\(\begin{cases}
x=k_1*b_1+a_1\\
x=k_2*b_2+a_2\\
\end{cases}\)
联立得\(k_1*b_1-k_2*b_2=a_2-a_1\)这个方程有解当且仅当\(gcd(k_1,k_2)|(a_2-a_
1)\)
则我们得到一组特解\((k_1,k_2)\)使得上述两个方程成立,带入得出\(x=x_{1,2}\)的特解
得\(x\equiv x_{1,2} \bmod lcm(b_1,b_2)\)
重复此过程得解
实现(luogu P4777):
//May all the beauty be blessed.
#include<bits/stdc++.h>
#define int __int128
using namespace std;
long long n;
int ax,bx,a[100010],b[100010];
void exgcd(int al,int bl,int &x,int &y){
if(!bl) x=1,y=0;
else exgcd(bl,al%bl,y,x),y-=al/bl*x;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
cin>>n;
for(int i=1;i<=n;i++){
long long x,y;
cin>>x>>y;
a[i]=x,b[i]=y;
}
ax=a[1],bx=b[1];
for(int i=2;i<=n;i++){
int x,y;
exgcd(ax,a[i],x,y);
int d=__gcd(ax,a[i]);//在这里可以特判有无解(d|(b[i]-bx))
x=x*(b[i]-bx)/d;//得到一组特解
x=(x%a[i]+a[i])%a[i];//用另一个模数对其取余,保证解的正确性
// cout<<x<<" ";
bx+=x*ax;
ax=ax*a[i]/d;//lcm(a[i],ax)
bx=(bx%ax+ax)%ax;
}
long long y=bx;
cout<<y;
}
拉格朗日插值法
据说其与\(crt\)有很深的联系,但我没看出来
已知\(f\)是一个多项式,并给出\(n\)个对应的点值:\(f(x_1)=y_1,f(x_2)=y_2...,f(x_n)=y_n\)
求次此多项式(或是\(f(x_k)=?\))
想法:暴力构造一系列多项式,使得\(f_i(x_i)=1\)且\(f_j(x_j)=0 (i!=j)\)
再加到一起构成\(f(x)=y_1f_1(x_1)+y_2f_2(x_2)+...+y_nf_n(x_n)\)
于是我们来考虑如何构造一个多项式\(f_i\)满足条件,
一个比较直接的想法是$$f_i(x)=\prod_{j!=i} (x-x_j)$$
而为了让\(f_i(x_i)=1\),我们令原多项式除以\(x=x_i\)时对应的值
最终求得$$f_i(x)=\prod_{j!=i} \frac{(x-x_j)}{(x_i-x_j)}$$
而自然$$f(x)=\sum_{i=1}^n\ y_if_i(x)$$
数论函数(待补)
数论函数:定义域为正整数的函数,可以视作数列
加性函数:
积性函数:\