数论知识荟萃

有参考算法竞赛进阶指南。。

一、质数

  • 定义:质数(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)\)
  1. 计算式
    \(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;
}
  1. 性质
    ①若\(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\)。即它们是成对存在的。
    对于以上证明,其实自己多证几遍就记住了。

  2. 求解\(φ(N)\)
    \(N\)分解质因数后,代入定义式计算。
    复杂度:\(O(\sqrt{N})\)

  3. 求解\(φ(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)同余的性质:

  1. \(a≡b\) \((mod\) \(n)\) \(\Leftrightarrow\) \(n|a-b\)
  2. \(a≡b\) \((mod\) \(n)\),且\(c≡d\) \((mod\) \(n)\)
    \(a+c≡b+d\) \((mod\) \(n)\)
    \(ac≡bd\) \((mod\) \(n)\)
  3. \(ka≡kb\) \((mod\) \(n)\) (k为任意整数)
    \(ab≡ac\) \((mod\) \(n)\),设\(d=(a,n)\),则\(b≡c\) \((mod\) \(n/d)\)
  4. \(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\)两两互质

\[\begin{equation} \left\{ \begin{aligned} x ≡ b_1 (mod \ m_1) \\ x ≡ b_2 (mod \ m_2) \\ ... \\ x ≡ b_n (mod \ m_n) \\ \end{aligned} \right. \end{equation} \]

方法:先找到整数\(L_1\),使得\(L_1≡1(mod \ m_1),b_1|L_1,b_2|L_1,...,b_n|L_1\)
\(L_1\)是同余方程

\[\begin{equation} \left\{ \begin{aligned} x ≡ 1 (mod \ m_1) \\ x ≡ 0 (mod \ m_2) \\ ... \\ x ≡ 0 (mod \ m_n) \\ \end{aligned} \right. \end{equation} \]

的解。

\(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

posted @ 2018-05-30 17:47  露迭月  阅读(503)  评论(2编辑  收藏  举报