基础数论

1 数论基础

1.1 取模

\((a+b)\mod c=(a\mod c + b\mod c)\mod c\)

\((a-b)\mod c=(a\mod c - b\mod c)\mod c\)

\((a\times b)\mod c=(a\mod c \times b\mod c)\mod c\)

1.2 整除

若存在整数 \(c\) 使得 \(a\times c =b\),则说 \(b\)\(a\) 的倍数,\(a\)\(b\) 的因数,记作 \(a\mid b\),若不存该整数则记作 \(a\nmid b\)

整除的性质:

  • \(a\mid b\iff\pm a\mid\pm b\).
  • \(a\mid b \and b\mid c \iff a\mid c\)
  • \(a\mid b \and b\mid a \iff \left|a\right|=\left|b\right|\)

1.3 最大公因数

1.3.1 更相减损术

平均时间复杂度为 \(O(\log n)\),最坏时间复杂度为 \(O(n)\)

虽然通常情况下时间复杂度较高,但是在处理大整数(高精度)时,运行效率可能较高。

int gcd(int a,int b){
    if(a == b){
        return a;
	}
	return gcd(min(a,b),abs(a-b));
}

注意:当 \(a\)\(b\) 相差过大时,代码的运行速度会非常满,甚至可以卡到 \(O(\max(a,b))\) 左右。

1.3.2 辗转相除法

时间复杂度为 \(O(\log n)\)

代码简洁,是最常用的 \(\gcd\) 算法。

int gcd(int a,int b){
    return b==0?a:gcd(b,a%b);
}

1.3.3 Binary GCD

虽然,该算法的时间复杂度同样也是 \(O(\log n)\),但绝大部分情况下,所需的时间要小于辗转相除法。

int gcd(int a,int b){
	int aa = __builtin_ctz(a);
	int bb = __builtin_ctz(b);
	int c = min(aa,bb);
	b >>= bb;
	while(a){
		a >>= aa;
		int t = a-b;
		aa = __builtin_ctz(a-b);
		b = min(a,b);
		a = abs(t);
	}
	return b<<c;
} 

1.4 快速幂

int pow(int a,int b,int p){
	int ans = 1;
    while(b){
		if(b&1){
			ans *= a;
            ans %= p;
        }
        a *= a;
        a %= p;
        b >> 1;
    }
    return ans;
}

1.5 互质

\(\gcd(a,b)=1\),则称 \(a\)\(b\) 互质。

1.6 质数

1.6.1 相关定义

  • 质数和合数:若 \(\forall i\in[2,n-1],i\nmid n\),则称正整数 \(n\) 为质数(或素数),否则则称 \(n\) 为合数,特别地,\(1\) 为合数。
  • 质因数:若 \(i\in P\and i\mid n\),则称 \(i\)\(n\) 的质因数。

1.6.2 判断质数

1.6.2.1 暴力枚举

时间复杂度 \(O(\sqrt n)\)

bool is_prime(int n){
	for(int i=2;i*i<=n;i++){
        if(n%i == 0){
            return false;
        }
    }
    return true;
}

1.6.2.2 Millar Robin

\(n\in P \implies a^d\equiv1\pmod n \or i\in [0,r),a^{d\times 2^i}\equiv n-1\pmod n\)

bool millar_robin(int n,int a){
    int d = n-1,r=0;
    while(!(d&1)){
        d >>= 1,r++;
	}
    int x = pow(a,d,n);
    if(x == 1){
		return true;
    }
    for(int i=0;i<r;i++){
		if(x = n-1){
			return true;
        }
        x = 1ll*x*x%n;
    }
    return false;
}
int prime[] = {2,3,5,7,13,23,37,73};
bool is_prime(int n){
	if(n < 2){
		return false;
    }
    if(int i=0;i<8;i++){
		int a = prime[i];
        if(!millar_robin(n,a)){
			return false;
        }
    }
    return true;
}

1.6.2.3分解因数

for(int i=2;i*i<=a;i++){
	if(a%i == 0){
		cnt ++;
        prime[cnt] = i;
        while(a%i == 0){
            num[cnt]++;
            a /= i;
        }
    }
}
if(x != 1){
	cnt ++;
    prime[cnt] = x;
    num[cnt] = 1;
}

1.7 约数

1.7.1 性质

  • 约数个数定理:若正整数 \(n=\prod_{i=1}^sp_i^{a_i}\),则其约数个数为 \(\prod_{i=1}^s(a_i+1)\)
  • 约数和定理:若正整数 \(n=\prod_{i=1}^sp_i^{a_i}\),则其约数和为 $\prod_{i=1}^s \sum_{j=0}{a_i}p_ij $。

1.7.2 线性筛法

1.7.2.1 约数个数

vector<int> prime;
int a[N],d[N];
bool vis[N];
void solve(int n){
	d[1] = 1;
	for(int i=2;i<=n;i++){
		if(!vis[i]){
			prime.push_back(i);
			a[i] = 1,d[i] = 2;
		}else{
			for(auto j:prime){
				if(i*j > n){
					break;
				}
                vis[i*j] = true;
				if(i%j == 0){
					a[i*j] = a[i] + 1;
					d[i*j] = d[i] / a[i*j] * (a[i*j]+1);
					break;
				}else{
					a[i*j] = 1;
					d[i*j] = d[i] * 2;
				}
			}
		}
	}
}

1.7.2.2 约数和

void solve(int n){
	s[1] = 1;
	for(int i=2;i<=n;i++){
		if(!vis[i]){
			prime.push_back(i);
			g[i] = s[i] = i+1;
		}else{
			for(auto j:prime[i]){
				if(i * j > n){
					continue;
				}
				vis[i*j] = true;
				if(i % j == 0){
					g[i*j] = g[i]*j+1;
					s[i*j] = s[i]/g[i]*g[i*j];
				}else{
					g[i*j] = j+1;
					s[i*j] = s[i]*g[i*j];
				}
			}
		}
	}
}

1.8 同余类和剩余系

1.8.1 同余类

对非零整数 \(m\),把全体整数分成 \(|m|\) 个两两不交的集合,且同一个集合中的任意两个数模 \(m\) 均同余,我们把这 \(|m|\) 个集合均称为模 \(m\) 的同余类或剩余类。用 \(r\bmod m\) 表示含有整数 \(r\) 的模 \(m\) 的同余类。

1.8.2 完全剩余系

1.8.3 简化剩余系

2 威尔逊定理

\((p-1)!\equiv \begin {array}{l} \left\{\begin{matrix} -1,p\in P\\ 2,p=4\\ 0,otherwise \end{matrix}\right. \end{array}\pmod p\)

3 欧拉函数

3.1 定义

\(\varphi(n)\) 表示的是小于等于 \(n\)\(n\) 互质的数的个数。

3.2 性质

  • 欧拉函数是积性函数,即若 \(gcd(a,b)=1\)\(\varphi(ab)=\varphi(a)\varphi(b)\)
  • \(p\in\mathbb{P}\)\(\varphi(p)=p-1,\varphi(p^k)=p^k-p^{k-1}\)
  • $\varphi(n)=n\times \prod_{i-1}^s \frac{p_i-1}{p_i} $。

3.3 实现

时间复杂度 \(O(\sqrt n)\)

int solve(int n){
	int phi = n;
    for(int i=2;i*i<=n;i++){
        if(n%i == 0){
            phi = phi/i*(i-1);
            while(n%i == 0){
                n /= i;
            }
        }
    }
    if(n != 1){
        phi = phi/n*(n-1);
    }
    return phi;
}

\([1,n]\) 的欧拉函数,时间复杂度 \(O(n)\)

int solve(int n){
	int 
}

3.4 欧拉定理

3.4.1 定义

  • \(gcd(a,m)=1 \implies a^{\varphi(m)}\equiv1\pmod m\)

3.5 扩展欧拉定理

\(a^b= \begin {array}{l} \left\{\begin{matrix} a^b,b<\varphi(m) \\ a^{b\bmod \varphi(m)+\varphi(m)},b\geq\varphi(m) \end{matrix}\right. \end{array}\pmod m\)

4 莫比乌斯函数

4.1 定义

\(\mu(n) \begin {array}{l} \left\{\begin{matrix} -1,n\in \mathbb{P} \\ 0,\exists a_i>1 \\ (-1)^m,otherwise \end{matrix}\right. \end{array}\)

4.2 线性筛法

void solve(int n){
	mu[1] = 1;
	for(int i=2;i<=n;i++){
		if(!vis[i]){
			prime.push_back(i);
			mu[i] = -1;
		}else{
			for(auto j:prime){
				if(i*j > n){
					break;
				}
				vis[i*j] = true;
				if(i%j){
					mu[i*j] = 0;
					break;
				}else{
					mu[i*j] = -mu[i];
				}
			}
		} 
	}
}

5 逆元

5.1 定义

\(\exists x,ax\equiv1\pmod b\),则这个正整数 \(x\) 称作 \(a\mod b\) 的逆元。

5.2 求逆元

5.2.1 费马小定理求逆元

费马小定理:\(\forall gcd(a,p)=1\and p\in P,a^{p-1}\equiv1\pmod p,a^p\equiv a\pmod p\)

\(\because ax\equiv1\pmod b\)

\(\therefore ax\equiv a^{b-1}\pmod b\)

\(\therefore x\equiv a^{b-2}\mod b\)

注意费马小定理求逆元,只适用于 \(b\in P\and gcd(a,b)=1\) 的情况下。

5.2.2 欧拉定理求逆元

\(\because ax\equiv1\pmod b\)

\(\therefore ax\equiv a^{\varphi(b)}\pmod b\)

\(\therefore x\equiv a^{\varphi(b)-1}\mod b\)

只适用于 \(gcd(a,b)=1\) 的情况。

5.2.3 线性求逆元

inv[1] = 1;
for(int i=2;i<=n;i++){
	inv[i] = (long long)(p-p/i)*inv[p%i]%p;
}

5.2.4 线性求任意两个数的逆元

s[0] = 1;
for(int i=1;i<=n;i++){
	s[i] = (a[i]*s[i-1]) % p;
}
sn[n] = pow(s[n],p-2,p);
for(int i=n-1;i>0;i--){
	sn[i] = (sn[i+1] * a[i+1]) % p;
}

6 扩展欧几里得定理(exgcd)

给定方程 \(ax+by=gcd(x,y)\),求任意一组满足条件的 \(a,b\)

6.1 代码实现

int exgcd(int a,int b,int %x,int &y){
	if(b == 0){
        x = 1;
        y = 0;
        return a;
    }
    int xx,yy;
    int g = exgcd(b,a%b,xx,yy);
    x = xx,y = xx-yy*(a/b);
    return g;
}

6.2 裴蜀定理

  • \(\forall x,y,gcd(a,b)\mid ax+by\)
  • \(\exists x,y,ax+by=gcd(a,b)\)

中国剩余定理(CRT)

定义

中国剩余定理可用于求如下形式的一元线性同余方程。

\[\left\{ \begin{array}{**lr**} x\equiv r_1\pmod{m_1}, & \\ x\equiv r_2\pmod{m_2}, & \\ \quad\quad\quad\quad\vdots&\\ x\equiv r_k\pmod{m_k}, & \\ \end{array} \right. \]

其中 \(gcd(m_1,m_2,\dots,m_k) =1\)

求解

  1. \(M=\prod m_i\)

  2. 计算第 \(i\) 个方程的解 \(c_i=\frac{M}{m_i}\)

  3. 计算 \(c^{-1}\pmod M\)

  4. \(x=\sum^n_{i=1} r_i,c_i,c_i^{-1}\pmod M\)

大步小步算法 (BSGS)

定义

大步小步算法(baby-step giant-step,BSGS)通常用于求解 \(a^x\equiv b\pmod p,gcd(a,p) = 1\) 的问题。

时间复杂度 \(O(\sqrt{p})\)

分析

\(x=i\times m-j\),其中 \(m=\lceil p\rceil,i\in [1,m],j\in[0,m-1]\),则 \(a^{i\times m-j}\equiv b\pmod p\),即 \((a^m)^i\equiv b\times a^j\pmod p\)

所以,求出所有的 \((a^{m})^i\)\(b\times a^j\) 即可。

实现

ll p, a, b;
scanf("%lld%lld%lld", &p, &a, &b);
ll m = ceil(sqrt(p));
ll t = b % p;
hash_table[t] = 0;
for (int i = 1; i <= m; i++) {
    t = (ll) t * a % p;
    hash_table[t] = i;
}
t = pow_mod(a, m, p);
ll now = 1;
for (int i = 0; i <= m; i++) {
    if (hash_table.count(now)) {
    	printf("%lld\n", i * m - hash_table[now]);
        return 0;
    }
    now = (ll) now * t % p;
}
printf("no solution\n");

组合数学

排列组合

加法原理和乘法原理

完成一件事有 \(N\) 类方法,每类方法有 \(a_i\) 种方法,那么一共有 \(\sum a_i\) 种选法。

完成一件事有 \(N\) 个步骤,每个步骤有 \(a_i\) 种方法,那么一共有 \(\prod a_i\) 种选法。

排列组合基础

排列

\(n\) 个元素选 \(m\) 个元素,按一定的顺序排列。

\(P^m_n=\frac{n!}{(n-m)!}\)

组合

\(n\) 个元素选 \(m\) 个元素,不考虑顺序。

\(C^m_n=\frac{n!}{m!(n-m)!}=\frac{p^m_n}{m!}\)

\(C_n^m=C_n^{n-m}\)

\(\sum_{i=0}^n C_n^m=2^n\)

二项式定理

\((a+b)^n=\sum_{i=0}^n C_n^ia^{n-i}b_i\)

卢卡斯定理

\(C_n^m \mod p=C_{\lfloor n\div p\rfloor}^{\lfloor m\div p\rfloor}\times C_{n\mod p}^{m_\mod p}\mod p,p\in P\)

代码实现如下:

int c(int n,int m,int p){
	if(m > n){
		return 0;
	}else{
		return (ll)f[n]*g[m]*g[n-m]%p;
	}
}
int lucas(int n,int m,int p){
	if(m == 0){
		return 1;
	}
	return (ll)lucas(n/p,m/p,p) * c(n%p,m%p,p) %p;
}

lucas 函数递归的边界为 \(m=0\)

注意,要特判 \(m>n\) 的情况。

恒等式

  • \(C^{m}_{n+1} = C^m_n\times\frac{n+1}{n-m+1}\)
  • \(\sum^n_1 C^i_n = 2^n\)
  • \(\sum^1_mC^i_n = C_{n+1}^{m+1}\)

高斯 (Gauss) 消元法

定义

用于求解线性方程:

\[\left\{ \begin{array}{**lr**} a_{11}x_1 + a_{12}x_2+\dots a_{1n}x_n=b_1 & \\ a_{21}x_1 + a_{22}x_2+\dots a_{2n}x_n=b_2 \\ \quad\quad\quad\quad\vdots&\\ a_{n1}x_1 + a_{n2}x_2+\dots a_{nn}x_n=b_n& \\ \end{array} \right. \]

步骤

一、将系数矩阵消为上三角矩阵

  1. 枚举主元,找到主元下面系数不是 \(0\) 的一行;
  2. 交换两行,把这一行与主元交换;
  3. 将该行同乘一个数,使主元的系数变为 \(1\)
  4. 把该行的若干被加到其他行,使主元下面的系数变为 \(0\)

二、逐个带入求解

此时,我们发现,\(a_n\) 已经知道了,我们将 \(a_n\) 的值带入其他的方程求解即可。

三、无解和无数解的判断

带入求解完成后,若:

  • \(\exist i\in[1,n],\forall j\in[1,n],a_{i,j}=0,a_{i,n+1}\neq0\),则方程无解;
  • 在方程有解的前提下 \(\exist i\in[1,n],\forall j\in[1,n+1],a_{i,j}=0\) 则方程有无数解。

实现

时间复杂度 \(O(n^3)\)

double a[N][N];
const double eps = 1e-6; 
bool gauss(int n){
	for(int i=1;i<=n;i++){
		int j;
		for(j=i;j<=n;j++){
			if(fabs(a[j][i]) > eps){
				break;
			}
		}
		swap(a[i],a[j]);
		if(fabs(a[i][i]) < eps){
			return 0;
		}
		for(j = n+1;j>=i;j--){
			a[i][j] /= a[i][i];
		}
		for(j = i+1;j<=n;j++){
			for(int k=n+1;k>=i;k--){
				a[j][k] -= a[j][i] * a[i][k];
			}
		}
	}
	for(int i=n-1;i>=1;i--){
		for(int j=i+1;j<=n;j++){
			a[i][n+1] -= a[i][j] * a[j][n+1];
		}
	}
	return 1;
}

例题

Luogu-P2455

本题重点考察无解和无穷解的判断。

#include<bits/stdc++.h>
using namespace std;
const int N = 1e2+5;
double a[N][N];
const double eps = 1e-6; 
bool gauss(int n){
	for(int i=1;i<=n;i++){
		int j;
		for(j=i;j<=n;j++){
			if(fabs(a[j][i]) > eps){
				break;
			}
		}
		j = min(j,n);
		swap(a[i],a[j]);
		if(fabs(a[i][i]) < eps){
			continue;
		}
		for(j = n+1;j>=i;j--){
			a[i][j] /= a[i][i];
		}
		for(j = i+1;j<=n;j++){
			for(int k = n+1;k>=i;k--){
				a[j][k] -= a[i][k] * a[j][i];
			}
		}
	}
	bool flag = true;
	bool fflag = false;
	for(int i=n;i>=1;i--){
		for(int j=i+1;j<=n;j++){
			a[i][n+1] -= a[j][n+1] * a[i][j];
			a[i][j] = 0;
		}
		bool flag = true;
		for(int j=1;j<=n;j++){
			if(fabs(a[i][j]) > eps){
				flag = false;
			}
		}
		if(flag == true && fabs(a[i][n+1]) > eps){
			puts("-1");
			return 0;
		}else if(flag == true){
			fflag = true;
		}
	}
	if(fflag == true){
		puts("0");
		return 0;
	}else{
		return 1;
	}
}
int main(){
	int n;
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n+1;j++){
			scanf("%lf",&a[i][j]);
		}
	}
	if(gauss(n)){
		for(int i=1;i<=n;i++){
			printf("x%d=%.2f\n",i,a[i][n+1]);
		}
	}
}

ACwing-208

高斯消元解异或方程组。

高斯消元模板为 \(O(n^3)\) 可以通过状态压缩变为 \(O(\frac{n^3}{w})\),对于本题而言,可以优化到 \(O(n^2)\)

注意位运算的优先级问题!

矩阵

struct node{
	int n,m;
    int z[105][105];
};

设矩阵 \(a\)\(n\)\(m\) 列。

设矩阵 \(b\)\(x\)\(y\) 列。

单位矩阵和数量矩阵

对于 \(n\times n\) 的矩阵 \(E\),若 \(\forall i\in\left[1,n\right],E_{i,i}=1 \and \forall i,j\in \left[1,n\right],i\neq j,E_{i,j}=0\),则该矩阵 \(E\) 为单位矩阵。

矩阵 \(kE\) 为数量矩阵。

单位矩阵的性质

  • \(AE=A,EA=A\)

矩阵的数乘

\(ans_{i,j}=a_{i,j}*k\)

矩阵加减法

当且仅当 \(n=x\and m=y\) 时,两个矩阵可以相加减。

\(ans_{i,j}=a_{i,j}+b_{i,j}\)

\(ans_{i,j}=a_{i,j}-b_{i,j}\)

矩阵乘法

当且仅当 \(m=x\) 时,两个矩阵可以相乘。

\(ans_{i,j}=\sum a_{i,k}+b_{k,j}\)

矩阵乘法的性质

  • 结合律,即 \(A(BC)=(AB)C\)

  • 左右分配律,即 \(A(B+C)=AB+AB,(B+C)A=BA+CA\)

  • 对数乘的结合性,即 \(\lambda(AB)=A(\lambda B)\)

  • 矩阵满足结合律,当且仅当其中一个矩阵相对于另一个矩阵为单位矩阵、数量矩阵或伴随矩阵。 \(AB=BA \iff B=kE\or B=A^*\)

代码实现

matrix operator*(const matrix &m1,const matrix &m2){
    m3.n = m1.n;
    m3.m = m2.m;
    for(int i=1;i<=m3.n;i++){
    	for(int j=1;j<=m3.m;i++){
			for(int k=1;k<=m1.m;k++){
				m3.z[i][j] += m1.z[i][k]*,m2[k][j];
            }
        }    
	}
}

由于内存缓存机制,通常情况下,以 ikj 的顺序枚举的速度相对最快。

应用

斐波那契数列

递推公式

递推式一 O(n):f_n=f_{n-1}+f_{n-2}。

递推式二 O(\log n)f_{2i+1}=f2_{i+1}+f2_{i}。

矩阵乘法

\begin{bmatrix} f_{i-1} & f_{i-2} \ \end{bmatrix}\times \begin{bmatrix} 1 & 1 \1&0\end{bmatrix}=\begin{bmatrix} f_{i} & f_{i-1} \ \end{bmatrix}

矩阵乘法可以配合快速幂使用,时间复杂度为 O(\log n)。

推广

若递推式变为 f_n=f_{n-1}+f_{n-3}。

则矩阵乘法变为:

\begin{bmatrix} f_{i-1} & f_{i-2}&f_{i-3} \ \end{bmatrix}\times \begin{bmatrix} 1 & 1 &0 \0&0&1\1&0&0\end{bmatrix}=\begin{bmatrix} f_{i} & f_{i-1}&f_{i-2} \ \end{bmatrix}

posted @ 2023-12-06 20:00  WhileTureRP++  阅读(21)  评论(1)    收藏  举报