数论知识荟萃
有参考算法竞赛进阶指南。。
一、质数
- 定义:质数(prime number)又称素数,有无限个。一个大于1的自然数,除了1和它本身外,不能被其他自然数整除,则称之为质数。
(1) 判定:
对于数\(N\),若之为合数,则存在一个数\(T\)能整除它其中,\(2<=T<=\sqrt{N}\)
复杂度:\(O(\sqrt{n})\)
(2) 筛法:
对于数\(N\),我们要求出\(1\) ~ \(N\)的所有素数。
直接介绍线性筛法,对于数\(m\),我们考虑仅用它的最小质因子\(q\)筛去它,这是线筛的最基本思想。
#include <cstdio>
const int N=1000010;
int v[N],prime[N],cnt=0,n;
//v[i]代表i的最小质因子,prime[i]代表第i的素数是多少
void Prime()
{
for(int i=2;i<=n;i++)
{
if(!v[i])
{
v[i]=i;
prime[++cnt]=i;
}
for(int j=1;j<=cnt;j++)
{
int k=prime[j]*i;
if(v[i]<prime[j]||k>n) continue;
v[k]=prime[j];
}
}
}
int main()
{
scanf("%d",&n);
Prime();
for(int i=1;i<=cnt;i++)
printf("%d ",prime[i]);
return 0;
}
复杂度:\(O(n)\)
(3) 质因数分解
- 算术基本定理:任何一个大于1的整数都能被分解成有限个质数的乘积
即\(N=p_1^{c^1}p_2^{c^2}...p_m^{c^m}\)或\(N=\prod_{i=1}^m{p_i}^{c_i}\)
当不考虑顺序时,分解具有唯一性
这点在后面用的很多。
- 质因数分解:
和判定是否是质数有点像,我们用\(1\) ~ \(\sqrt{N}\)中的每一个数去试除\(N\)
复杂度:\(O(\sqrt{N})\)
二、约数
(1) 整除,约数
整除的概念:一般的,设a,b为整数,且b≠0.如果存在整数q,使得a=bq,称b整除a,记作\(b|a\),也称b是a的约数。如果p不存在,称b不整除a,记作\(b \nmid a\).
整除的性质:
a|b,b|a \(\Rightarrow\) a=b或a=-b
a|b,b|c \(\Rightarrow\) a|c
a|b,a|c \(\Rightarrow\) 对任意整数x,y,有a|bx+cy
若\(a|bc\),且\((a,b)\)=\(1\),则\(a|c\)
设p为素数,若\(p|ab\),则\(p|a\)或\(p|b\)
设p为素数,若\(p|a_1a_2...a_k\),则存在\(a_i\) \((1≤i≤k)\),使得\(p|a_i\).
设整数 \(a\) , \(b\) 不同时为0,则存在一对整数 \(m\) , \(n\) ,使得\((a,b)=am+bn\)(在一次同余方程和不定方程中经常用到)【裴蜀定理】
(2) 最大公约数与最小公倍数
-
定义:\(gcd(a,b)\)(或\((a,b)\))为最大公因数,\(lcm[a,b]\)(或\([a,b]\))为最小公倍数
-
欧几里得算法:\((a,b)=(b,a\) \(mod\) \(b)\)
欧几里得就不证明了吧。
int gcd(int a,int b)
{
return b==0?a:gcd(b,a%b);
}
- \((a,b)[a,b]=|a||b|\)
(3) 算术基本定理的推论:
\(N=p_1^{c^1}p_2^{c^2}...p_m^{c^m}\)
-
\(N\)的正约数个数:
\(\prod_{i=1}^m (c^i+1)\) -
\(N\)的正约数之和:
\((1+p_1+p_1^2+...+p_1^{c_1})*...*(1+p_m+p_m^2+...+p_m^{c_m})=\prod_{i=1}^m(\sum_{j=0}^{c_i} (p_i)^j)\)
(4) 互质
对整数\(a,b\),若\(gcd(a,b)=1\),则称\(a\)与\(b\)互质。
(5) 欧拉函数
- 定义:\(1\) ~ \(N\)中与\(N\)互质的数的个数,称为欧拉函数,记为\(φ(N)\)
- 计算式
对\(N\)进行算术基本定理分解,即\(N=p_1^{c^1}p_2^{c^2}...p_m^{c^m}\)或\(N=\prod_{i=1}^m{p_i}^{c_i}\)
则\(φ(N)=(1-1/p_1)*(1-1/p_2)*...*(1-p_m)\)即\(φ(N)=\prod_{i=1}^m(1-1/p_i)\)
感性证明(即并不是那么确切的,只是能加深记忆的证明·):
对于\(N\)的某个质因子\(p\),\(p*k\)一定于\(N\)不互质(\(k\in N^*,k*p<N\)),即筛去后为\(N-N/p\)
若此时引入第二个因子\(q\),同理筛去\(N/q\),但是多筛去了\(q\)与\(p\)的公共倍数,加回来,即为
\(N-N/p-N/q+N/(q*p)=N(1-1/p)(1-1/q)\),以此类推
计算式\(O(\sqrt N)\)求解\(φ(N)\)
ll get(ll k)
{
ll eu=k;
for(ll i=2;i*i<=k;i++)
{
if(k%i==0)
eu=eu*(i-1)/i;
while(k%i==0)
k/=i;
}
if(k>1) eu=eu*(k-1)/k;
return eu;
}
-
性质
①若\(gcd(a,b)=1\),则\(φ(ab)=φ(a)*φ(b)\)
感性证明:带入欧拉函数定义式即可。
【拓展】
完全积性函数:是指所有对于任何\(a,b\)都有性质\(f(ab)=f(a)f(b)\)的数论函数。
积性函数:是指所有对于\(gcd(a,b)=1\)的\(a,b\)都有性质\(f(ab)=f(a)f(b)\)的数论函数。
②若质数\(q\)满足\(q|n\)且\(q^2|n\),则\(φ(q)=φ(n/q)*q\)
代入计算式可以得到
③若质数\(q\)满足\(q|n\)且\(q^2 \nmid n\),则\(φ(q)=φ(n/q)*(q-1)\)
由积性函数性质得到
④\(\sum_{d|n}φ(d)=n\)
先证明是积性函数,再讨论单因子情况即可
⑤\(φ(n)*n/2=\sum_{d},gcd(d,n)=1\)
若\(gcd(x,n)=1\),则\(gcd(n-x,n)=1\)。即它们是成对存在的。
对于以上证明,其实自己多证几遍就记住了。 -
求解\(φ(N)\)
将\(N\)分解质因数后,代入定义式计算。
复杂度:\(O(\sqrt{N})\) -
求解\(φ(1)\)~\(φ(N)\)
借助性质①②③和线性筛的思想。
我们在线性筛筛去合数的同时推出这个合数的\(φ(i)\)
code:
int v[N],prime[N],phi[N],cnt=0,n;
void eular()
{
for(int i=2;i<=n;i++)
{
if(!v[i])
{
v[i]=i;
prime[++cnt]=i;
phi[i]=i-1;
}
for(int j=1;j<=cnt;j++)
{
int tmp=i*prime[j];
if(v[i]<prime[j]||tmp>n) break;
v[tmp]=prime[j];
phi[tmp]=phi[i]*(i%prime[j]?prime[j]-1:prime[j]);
}
}
}
三、同余
(1)同余的概念:一般的,设n为正整数,a和b为整数,如果a和b被n除后余数相同,那么称a和b模n同余,记作\(a≡b\) \((mod\) \(n)\)
(2)同余的性质:
- \(a≡b\) \((mod\) \(n)\) \(\Leftrightarrow\) \(n|a-b\)
- 若\(a≡b\) \((mod\) \(n)\),且\(c≡d\) \((mod\) \(n)\),
① \(a+c≡b+d\) \((mod\) \(n)\)
② \(ac≡bd\) \((mod\) \(n)\) - ①\(ka≡kb\) \((mod\) \(n)\) (k为任意整数)
②若\(ab≡ac\) \((mod\) \(n)\),设\(d=(a,n)\),则\(b≡c\) \((mod\) \(n/d)\) - \(a^m≡b^m\) \((mod\) \(n)\) (m为正整数)
这里证明一下第三条第二点
\(ab≡ac\) \((mod\) \(n)\) \(d=(a,n)\)
\(\Rightarrow n | a(b-c)\)
\(\Rightarrow n/d |a(b-c)/d\)
由\(gcd(n/d,a/d)=1\)
\(\Rightarrow n/d |(b-c)\)
\(\Rightarrow b≡c(mod n/d)\)
(3)一次同余方程求解(exgcd或者叫大衍求一术):
对于一次同余方程\(ax≡b(mod m)\)
\(\Rightarrow m|ax-b\)
设\(-ym=ax-b\)
即为\(ax+my=b\)
转化为求解一元二次不定方程
对\(ax+by=d\)
当\(gcd(a,b)|d\)时,有整数解
证明即求解方法:
由欧几里得:\(gcd(a,b)=gcd(b,r)=...=gcd(a_n,0)\)
使用数学归纳法
对最后一步:\(a_n*x_n+0*y_n=a_n\)
显然对这个方程有解\(x_n=1,y_n=0\)
若\(a_m*x_m+b_m*y_m=d\)有解
则对\(a_{m-1}*x_{m-1}+b_{m-1}*y_{m-1}=d\)
有\(b_{m-1}=a_m,a_{m-1}=\lfloor a_{m-1}/a_m\rfloor*a_m+b_m\)(gcd得出)
\(\Rightarrow (\lfloor a_{m-1}/a_m\rfloor *a_m+b_m)*x_{m-1}+a_m*y_{m-1}=d\)
\(\Rightarrow (k*x_{m-1}+y_{m-1})*a_m+x_{m-1}*b_m=d\)
\(\Rightarrow x_{m-1}=y_m,y_{m-1}=x_m-\lfloor a_{m-1}/a_m\rfloor *y_m\)
由以上,我们得到了它的证明和解法
(4)欧拉定理
若\(gcd(a,n)=1\),则有\(a^{φ(n)}≡1(mod\) \(n)\)
证明:
定义简化剩余类:把所有与整数a(a与n互质)模n同余的整数构成的集合叫做模n的一个简化剩余类,记作\(a[n]\),并把a叫做简化剩余类\(a[n]\)的一个简化剩余系。
先证明当集合\(x\)恰好遍历(即取遍)\(n\)每一个简化剩余系时,\(kx\)也遍历。(\(k\)为任意整数,\(gcd(x,n)=1\))
反证:若有\(kx_i≡kx_j (mod\) \(n)\)
则 \(x_i≡x_j (mod\) \(n)\)
矛盾,得证
下面欧拉定理:
设\({\overline{a_1},\overline{a_2},...,\overline{a_φ(n)}}\)是\(n\)的一个简化剩余类
由上\({\overline{a*a_1},\overline{a*a_2},...,\overline{a*a_φ(n)}}\)也是
则\(a*a_1*a*a_2...a*a_{φ(n)}≡a_1*a_2...a_{φ(n)} (mod\) \(n)\)
则\(a^{φ(n)}≡1(mod\) \(n)\)
特别的,当\(n\)取质数时,有\(φ(n)=n-1\)
则\(a^{n-1}≡1 (mod\) \(n)\),即为费马小定理
(5)乘法逆元
对于"+"、"-"、"*",我们都已经得到了它在mod p下的转换式,那么对于"/"呢?
定义:若整数\(b,m\)互质,并且\(b|a\),则存在一个整数\(x\),使得\(a/b≡a*x(mod\) \(m)\)。称\(x\)为\(b\)的乘法逆元,记为\(b^{-1}≡(mod\) \(m)\)
对于这个有解性可以转换成一次同余方程的有解来证明,不多赘述。
求法:\(a/b≡a*b^{-1}≡a/b*b*b^{-1}(mod\) \(m)\),即\(b*b^{-1}≡1(mod\) \(m)\),即转换为同余方程求解。特别的,当\(m\)为质数时,可以用费马小定理求解
- \(O(n)\)求解\(1\) ~ \(n(mod\) \(p)\)的逆元
假设\(p=k*i+r,k<i\),我们尝试用\(k^{-1}\)求\(i^{-1}\)
\(k*i+p≡0(mod\) \(p)\)
\(\Rightarrow k*i≡-r(mod\) \(p)\)
\(\Rightarrow k*i*i^{-1}*r^{-1}≡-r*r^{-1}*i^{-1} (mod\) \(p)\)
\(\Rightarrow -k*r^{-1}≡i^{-1} (mod\) \(p)\)
\(\Rightarrow i^{-1}≡-\lfloor p/i \rfloor *(p\) \(mod\) \(i)^{-1} (mod\) \(p)\)
其实,这本质上是利用了逆元也是积性函数的性质。
参考代码:
#include <cstdio>
#define ll long long
const int N=3000010;
ll n,p,inv[N];
int main()
{
scanf("%lld%lld",&n,&p);
inv[1]=1;printf("1\n");
for(int i=2;i<=n;i++)
{
inv[i]=((inv[p%i]*(p-p/i))+p)%p;
printf("%lld\n",inv[i]);
}
return 0;
}
- \(O(n)\)求解\(1!\)~\(n!\)的逆元(\(p\)为质数)
设第\(i\)项阶乘为\(f_i\),则有\(f_i=i*f_{i-1}\)
若已经求得\({f_i}^{-1}\)
则有\(i*{f_{i-1}}*{f_i}^{-1}≡f_{i-1}*{f_{i-1}}^{-1} \ (mod \ p)\)
化简得 \(f_{i-1}^{-1}≡i*{f_i}^{-1} \ (mod \ p)\)
参考代码:
void getinv()
{
inv[0]=1;
fac[0]=1;
for(int i=1;i<=n;i++)
fac[i]=(fac[i-1]*i)%mod;
inv[n]=quick_pow(fac[n],n-2);
for(int i=n-1;i;i--)
inv[i]=(inv[i+1]*(i+1))%mod;
}
(6)中国剩余定理(孙子定理)
求解一次同余方程组,其中\(m_1,m_2,...m_n\)两两互质
方法:先找到整数\(L_1\),使得\(L_1≡1(mod \ m_1),b_1|L_1,b_2|L_1,...,b_n|L_1\)
即\(L_1\)是同余方程
的解。
把\(L_1\)乘上\(b_1\),即满足了第一个方程,而其余无影响。
然后找到\(L_2,...,L_n\).
\(x=\prod_{i=1}^n L_i\)即为同余方程的解。
下面讨论如何得到\(L_i\)。
令\(M=\prod_{i=1}^n m_i\),设\(M_i=M/m_i\)
则\(M_i\)满足整除除了\(b_i\)的所有\(b\)
然后我们要求\(L_i≡1(mod \ b_i)\)
设\(M_i*t_i≡1(mod \ b_i)\)
即转换为了求解一次同余方程的问题。
我们对同余方程组进行\(n\)次同余方程的求解即可。
解为
\(x≡\prod_{i=1}^n M_i*t_i*b_i (mod \ M)\)
参考代码:中国剩余定理
四、组合计数
(1)加法原理与乘法原理
加法原理:做一件事,完成它可以有\(n\)类办法,在第一类办法中有\(m_1\)种不同的方法,在第二类办法中有\(m_2\)种不同的方法,……,在第\(n\)类办法中有\(m_n\)种不同的方法,那么完成这件事共有\(N=\sum{i=1}^n m_i\)种不同方法。每一种方法都能够直接达成目标。
乘法原理:做一件事,完成它需要分成\(n\)个步骤,做第一步有\(m_1\)种不同的方法,做第二步有\(m_2\)种不同的方法,……,做第\(n\)步有\(m_n\)种不同的方法,那么完成这件事共有\(N=\prod_{i=1}^n m_i\)种不同的方法。
(2)排列组合
从\(n\)个互异元素中依次取出\(m\)个元素存在顺序的排除一列,产生的不同排列的数量是
\(A_n^m=n*(n-1)*(n-2)*...*(n-m+1)=\frac{n!}{(n-m)!}\)
从\(m\)个互异元素中取出m个元素组成一个集合不存在顺序,产生的不同组合的数量是
\(C_n^m=\frac{A_n^m}{m!}=\frac{n!}{m!(n-m)!}\)
考虑取出\(m\)个元素会产生\(m!\)种顺序
- 组合数的性质
①\(C_n^m=C_n^{(n-m)}\)
感性证明:从集合中取出了\(m\)个元素就剩下了\(n-m\)个元素,方案数是相等的
②\(C_n^m=C_{n-1}^{m}+C_{n-1}^{m-1}\)(杨辉三角)
这一点十分重要,由此可以得出组合数的递推式。
感性证明:现在已经取到了第\(n\)个元素。我们有两个选择,取第\(n\)个元素或不取第\(n\)个元素
若取第\(n\)个元素,则先在前\(n-1\)个元素中取\(m-1\)个,为\(C_{n-1}^{m-1}\)
若不取第\(n\)个元素,则先在前\(n-1\)个元素中取\(m\)个,为\(C_{n-1}^m\)
根据加法原理,可以得到\(C_n^m=C_{n-1}^{m}+C_{n-1}^{m-1}\)
③\(\sum{i=0}^n C_n^i=2^n\)
感性证明:从\(n\)个互异元素中取出若干个组成一个集合,有\(n+1\)种方法,分别取出0,1,..n个元素,又由加法原理,有\(\sum{i=1}^n\)种方法
从另一种角度看,每个元素在原集合里都有两种情况,取或不取,方案数为\(2^n\)
以上也可以代入计算式进行验证。
- 组合数的求法
①用第二个性质,可以在\(O(n^2)\)求出0<=j<=i<=n的所有组合数\(C_i^j\)
void get()
{
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])%mod;
}
②用计算式在\(O(nlogn)\)求出某一个组合数\(C_i^j\)
因为结果一般较大,通常会用mod取一下模
所以先求出分母\(m!(n-m)!\)的逆元
void getinv()
{
inv[0]=1;
fac[0]=1;
for(int i=1;i<=n;i++)
fac[i]=(fac[i-1]*i)%mod;
inv[n]=quick_pow(fac[n],n-2);
for(int i=n-1;i;i--)
inv[i]=(inv[i+1]*(i+1))%mod;
}
int get(int i,int j)
{
return (fac[i]*inv[j]*inv[i-j])%mod;
}
(3) 二项式定理
\((x+y)^n=\sum_{i=0}^n C_n^i*a^i*b^{n-i}\)
这个其实手玩一下就出来了,用排列组合的思想考虑每一项出现的次数。
下面证明\(Lucas\)定理要用到
(4) \(Lucas\) 定理
若\(p\)是素数,则有
\(C_n^m≡C_{n\%p}^{m\%p}*C_{n/p}^{m/p} \ (mod \ p)\)
证明:
首先素数的条件用在这个地方
当\(p\)为质数时,任取\(x \in (1,p)且x \in N\),满足\(C_p^x≡0 \ (mod \ p)\)。这点不难,不证明了。
设\(n=ap+r_1,m=bp+r_2\)
取\((1+x)^n%p\)这样一个式子,我们对它进行变形(本质上对应将数进行p进制分解)
\((1+x)^n=(1+x)^{ap+r_1}=((1+x)^p)^a*(1+x)^{r_1}\)
\(≡(1+x^p)^a*(1+x)^{r_1}=\sum_{i=0}^a C_a^i*x^{i*p}*\sum C_{r_1=0}^j*x^j \ (mod \ p)\)(注意最后两步用了二项式定理化简,第三步用了那个没证明的玩意儿)
整理得\((1+x)^n≡\sum_{i=0}^a C_a^i*x^{i*p}*\sum C_{r_1=0}^j*x^j \ (mod \ p)\)
对左边这样一项\(x^{bp+r_2}\)来说,它的系数为\(C_{ap+r_1}^{bq+r_2}\)
而右边当且仅当\(i=b,j=r_2\)时,可以构成这个项,而它的系数为\(C_a^b*C_{r_1}^{r_2}\)
即\(C_n^m≡C_{n\%p}^{m\%p}*C_{n/p}^{m/p} \ (mod \ p)\),则得证
咕咕咕
开始更新组合数学 2018.6.29