【学习笔记】数学

欧拉函数

\(φ(x)\),小于等于 x 和 x 互质的数的个数。互质时满足积性。

\(x\) 为质数时,\(φ(x)=x-1\)

多个数
  1. \(i \bmod x = 0\)\(φ(ix)=i \times x \prod=i \times φ(x)\)
  2. \(i \bmod x \not = 0\)\(φ(ix) = φ(i)φ(x)\)
代码
for(int i = 2;i<=n;++i){
	if(!mark[i])e.push_back(i),phi[i] = i-1;
	for(int j = 0;j<e.size();++j){
		int x = e[j];
		if(x*i > n)break;
		mark[x*i] = 1;
		if(i % x){
			phi[i*x] = phi[i]*phi[x];
		}else{
			phi[i*x] = phi[i]*x; 
			break;
		}
	}
}
单个数

\(φ(n)=n*(1-\frac{1}{a1})*(1-\frac{1}{a2})*(1-\frac{1}{a3})*……*(1-\frac{1}{ak})\)

代码
int phi(int n){
	int ans = n;
	for(int i = 2;i*i<=n;++i){
		if(n%i == 0){
			ans = ans / i * (i-1);
			while(n % i == 0)n /= i;
		}
	}
	if(n > 1)ans = ans / n * (n-1);
	return ans;
}

费马小定理:

\(p\) 素,\(a\) 不是 \(p\) 的倍数,\(a^{p-1} ≡ 1\pmod p\)
故有 \(a ^ b ≡ a ^ {b \mod (p-1)} \pmod p\)

欧拉定理:

\(p > 0,gcd(a,p)=1\),则有 \(a^{φ(m)} ≡ 1\pmod p\)
故有:\(a ^ b≡a^{b\mod φ(m) } \pmod m\)

扩欧拉:

\(b \le φ(m), a ^ b ≡ a^b\)
否则 \(a^ b≡ a^{b \mod φ(m)+φ(m)}\)

威尔逊:

\(n \in N^{+}\),当且仅当 \(n\) 为素数,\((n-1)!≡-1 \pmod n\)

逆元:

  1. 扩欧几里得:
代码
int exgcd(int a,int b,int &x,int &y){
	if(b == 0){
		x = 1, y = 0;
		return a;
	}
	int d = exgcd(b,a%b,x,y);
	int t = x;
	x = y;
	y = t - a/b*y;
	return d;
}
/*
b x' + (a % b) y' = gcd
a x + by = gcd
求 x, y

b x' + (a - kb) y' = gcd
b x' + a y' - kb y' = gcd
a y' + b(x' - ky') = gcd
其中 k = a / b
x = y'
y = x' - a / b y'
*/
  1. 快速幂法
  2. 递推
代码
inv[0] = inv[1] = 1;
for(int i = 2;i<=n;++i)
	inv[i] = (mod - 1ll * inv[mod % i] * (mod / i) % mod) % mod;
/*
p = i * k + t
i * k + t = 0 (mod p)
k + t * inv[i] = 0(mod p)
inv[t] * k + inv[i] = 0(mod p)
-inv[t] * k = inv[i] (mod p)
inv[i] = (p - inv[p % i] * (p / i)) mod p
*/

裴蜀定理

存在 \(x,y\) 使得,\(ax + by = gcd(a, b)\)
任意 \(x,y\) 都有,\(gcd(a,b)|ax + by\)

CRT

\({x \equiv a_i\pmod {n_i}}\),模数互质,求解 \(x\)
\(N = \prod n_i, m_i = N / n_i\)\({m_i}^{-1}\)\(m_i\) 在模 \(n\) 意义下的逆元。
\(x = \sum_{i=1}^k a_im_i{m_i}^{-1} \pmod N\)

代码
int n,M = 1,a[N],b[N];
// ∑Mi * ti * ai 
inline int exgcd(int a,int b,int &x,int &y){
	if(!b){ x = 1; y = 0; return a; }
	int d = exgcd(b,a%b,x,y);
	int t = x;
	x = y; y = t - a / b * y;
	return d;
}
int CRT(){
	int ans = 0;
	for(int i = 1;i<=n;++i){
		int m = M / a[i],x = 0,y = 0;
		exgcd(m,a[i],x,y);
		ans = ((ans + m * x * b[i])%M + M)%M;
	}
	return ans;
}
signed main(){
	n = read();
	for(int i = 1;i<=n;++i)a[i] = read(),b[i] = read(),M = M * a[i];
	printf("%lld",CRT()); 
	return 0;
}

EXCRT

\({x \equiv a_i\pmod {n_i}}\),模数不互质,求解 \(x\)
不断合并两个方程。
\(x = n_1 p + a_1 = n_2 q + a_2\)
\(n_1 p - n_2 q = a_2 - a_1\)
由裴蜀定理,\(a_2 - a_1\) 不能被 \(gcd(n_1,n_2)\) 整除时,无解;
否则用扩展欧几里得算出可行解 \((p,q)\)
\(x \equiv b \pmod M\)\(b = n_1 p + a_1,M = \text{lcm}(n_1, n_2)\)

代码
#include<bits/stdc++.h>
#define print(a) cerr<<#a"="<<(a)<<endl
#define int long long
using namespace std;
const int N = 1e5 + 10;
int n,a[N],m[N];
/*
m1 * p + a1 = m2 * q + a2
m1 * p - m2 * q = a2 - a1
*/
int exgcd(int a,int b,int &x,int &y){
	if(b == 0){
		x = 1, y = 0;
		return a;
	}
	int d = exgcd(b,a%b,x,y);
	int t = x;
	x = y;
	y = t - a/b*y;
	return d;
}
int excrt(){
//	if(n == 1){
//		if(m[1] > a[1])return a[0] == 0 ? m[0] : a[0];
//		else return -1;
//	}
	int M = m[1], A = a[1] % m[1];
	for(int i = 2;i<=n;++i){
		a[i] %= m[i];
		int x,y,gcd = exgcd(M,m[i],x,y);
		int val = a[i] - A;
		if(val % gcd != 0)return -1;
		int P = m[i] / gcd;
		x = ((((__int128)x) * val / gcd) % P + P)%P;
		A = M * x + A;
		M = M * P;
	}
	return A == 0 ? A + M : A;
}
void solve(int cas){
	scanf("%lld",&n);
	for(int i = 1;i<=n;++i)scanf("%lld",&m[i]);
	for(int i = 1;i<=n;++i)scanf("%lld",&a[i]);
	printf("Case %lld: %lld\n",cas,excrt());
}
signed main(){
	int T; scanf("%lld",&T);
	for(int i = 1;i<=T;++i)solve(i);
	return 0;
}

高斯消元

代码
// 高斯-约旦消元
// https://www.luogu.com.cn/problem/P3389 
// 优点:实现行数:无需回带,较简单
// 其实可以判断无解和无数解 
#include<bits/stdc++.h>
#define print(a) cout << #a"=" << a << endl
#define debug() cout << "Line:" << __LINE__ << endl
#define sign() puts("----------")
#define double long double
using namespace std;
const int N = 1010;
const double eps = 1e-7;
double a[N][N],ans[N];
int n,m;
int solve(int n,int m){
	int r = 1;
	for(int c = 1;c<=n;++c){
		int mxr = r;
		for(int i = r+1;i<=m;++i)if(fabs(a[i][c]) > fabs(a[mxr][c]))
			mxr = i;
		if(fabs(a[mxr][c]) < eps)continue;
		if(mxr ^ r)swap(a[mxr],a[r]);
		for(int i = 1;i<=m;++i)if(i ^ r){
			for(int j = n+1;j>=c;--j)
				a[i][j] -= a[i][c] / a[r][c] * a[r][j];
		}
		++r;
	}
	--r;
	for(int i = r+1;i<=m;++i)if(fabs(a[i][n+1]) > eps)return -1;
	if(r == n){
		for(int i = 1;i<=n;++i){
			ans[i] = a[i][n+1] / a[i][i];
			(fabs(ans[i]) < eps) && (ans[i] = 0);
		}
		return 0;
	}
	return m - r;
}
int main(){
	scanf("%d",&n);
	for(int i = 1;i<=n;++i)
		for(int j = 1;j<=n+1;++j)scanf("%Lf",&a[i][j]);
	int res = solve(n,n);
	if(res == -1 || res > 0)puts("No Solution");
	else{
		for(int i = 1;i<=n;++i)printf("%.2Lf\n",ans[i] + eps);
	}
	return 0;
}	

插板法

cas1:求 \(x_1+x_2+\cdots+x_k=n\)的正整数解的组数:\(C_{n-1}^{k-1}\)

cas2:求 \(x_1+x_2+\cdots+x_k=n\)的非负整数解的组数:\(C_{n+k-1}^{k-1}=C_{n+k-1}^n\)

cas3:求 \(x_1+x_2+\cdots+x_k=n\)解的组数,\(x_i\ge a_i\)

\(x'_i = x_i - a_i,C_{n-\sum a+k-1}^{k-1} = C_{n-\sum a+k-1}^{n-\sum_a}\)

多重集合

\(S = \{n_i * a_i\},i\in[1,k]\)

全排列:\(\frac{totn!}{\prod n_i!}\)

组合(选择 \(r\) 个组成新的多重集的个数):
case1:\(r < n_i, \forall i\)\(C_{r+k-1}^{k-1}\)
case2:
\(\forall i \in[i,k],x_i \le n_i,\sum_{i=1}^kx_i=r\)
容斥。
全局:\(\sum_{i=1}^kx_i=r\),属性:\(x_i\le n_i\)

\(S_i\) 为满足属性 \(i\) 的集合,\(S'_i\) 为不满足属性 \(i\) 的集合(\(x_i \ge n_i+1\),同插板法中 cas3)。

\(ans = |\bigcap s_i|=|U|-|\bigcup s'_i| = \sum_{popcnt = 0}^k(-1)^{popcnt}\sum_A C_{r-(\sum_{A}n_{A_i}+p)+k-1}^{k-1}\)

错排

容斥推导:
全集:\(|U| = n!\),属性 \(P_i \not = i\),问题变为求 \(|\bigcup_{i=1}^nS'_i|\)
\(S'_i\) 即满足 \(P_i = i\) 的排列数量。又 \(|\bigcap_{i=1}^k S_{ai}| = (n-k)!\)
所以有:\(|\bigcup S'_i|=\sum_{k=1}^n(-1)^{k-1} \sum_{A}|\bigcap_{i=1}^kS_{ai}|=\sum_{i=1}^n(-1)^{k-1}C_{n}^{k}(n-k)!=\sum_{i=1}^n(-1)^{k-1}\frac{n!}{k!}=n!\sum_{k=1}^{n}\frac{(-1)^{k-1}}{k!}\)
因此 \(n\) 的错位排列数为:\(D_n = n! - n ! \sum_{k=1}^n\frac{(-1)^{k-1}}{k!}=n!\sum_{i=0}^n\frac{(-1)^{k}}{k!}\)

递推:
\(D_n=(n-1)(D_{n-1}+D_{n-2})\)

抽屉原理

构造中 trick

组合数推导

二项式定理

\((a+b)^n = \sum_{i=0}^{n}C_{n}^{i}a^{n-i}b^{i}\)

Catalan 数

\(C_n = \sum_{i=0}^{n-1}C_{i}C_{n-1-i},C_0 = 1\)
\(C_n = \frac{C_{2n}^n}{n+1}\)
\(C_n = C_{2n}^n - C_{2n}^{n+1}, n \ge 0\)
\(C_n = \frac{4n-2}{n+1}C_{n-1},n > 0, C_0 = 1\)

应用:

  1. 路径计数问题:有一个大小为 \(n\times n\) 的方格图,左下角为 \((0, 0)\),右上角为 \((n, n)\)。从左下角开始,每次都只能向右或者向上走一单位,不走到对角线 \(y=x\) 上方(但可以触碰)的情况下,到达右上角的路径总数为
    \(C_n\)
  2. 圆内不相交弦计数问题:圆上有 \(2n\) 个点,将这些点成对连接起来且使得所得到的 \(n\) 条线段两两不交的方案数是 \(C_n\)
  3. 三角剖分计数问题:对角线不相交的情况下,将一个凸 \((n+2)\) 边形区域分成三角形区域的方法数为 \(C_n\)
  4. 二叉树计数问题:含有 \(n\) 个结点的形态不同的二叉树数目为 \(C_n\)。等价地,含有 \(n\) 个非叶结点的形态不同的满二叉树数目为 \(C_{n}\)
  5. 括号序列计数问题:由 \(n\) 对括号构成的合法括号序列数为 \(C_n\)
  6. 出栈序列计数问题:一个栈(无穷大)的进栈序列为 \(1,2,3, \ldots ,n\),合法出栈序列的数目为 \(C_n\)
  7. 数列计数问题:\(n\)\(+1\)\(n\)\(-1\),满足所有前缀和 \(\ge 0\) 的序列个数为 \(C_n\)
posted @ 2025-10-30 19:07  Luzexxi  阅读(3)  评论(0)    收藏  举报