数学

数论与线性代数

1. 位运算

负数的二进制表达:正数表达 - 1,再取反
-8 ——>(正) 8:1000 ——>(- 1) 0111 ——>(取反) 1000
看负几:先取反,再 + 1
1000 ——>(取反) 0111 ——>(+ 1) 1000(8) ... -8
-8 ~ -1:1000, 1001, ..., 1111
 0 ~ 7 :0000, 0001, ..., 0111 
int c = 0b110	//二进制 6
int d = 0x4e	//十六进制 78 (0 ~ 9, a ~ f)
~	取反	相反数:取反,再 +1 (最小负数的相反数得不到)
|	或		每一位上只要有一个 "1", 就会留下来
&	与		每一位上两个都是 "1", 才会留下 "1"
^	异或	每一位上两个相同就是 "0", 不同就是 "1"
<<	左移
>>	>>>	右移	非负数, 效果一样。负数, >> 左边用符号位补, >>> 左边用 0 来补
非负数 
<< i	(* pow(2, i))
>> i 	(/pow(2, i))
//打印二进制
for(int i = 31; i >= 0; i--)
	if(a & (1 << i))	//若 i > 31, 把 1 写成 1L, long 类型
		cout << 1;
	else
		cout << 0;
(n >> k) & 1 		//取出整数 n 在二进制表示下的第 k 位	// 1 << k & n
n & ((1 << k) - 1)	//取出整数 n 在二进制表示下的第 0 ~ k - 1 位 (后 k 位)

n xor (1 << k)		//把整数 n 在二进制表示下的第 k 位取反
n | (1 << k)		//对整数 n 在二进制表示下的第 k 位赋值 1
n & (~ (1 << k))	//对整数 n 在二进制表示下的第 k 位赋值 0

n & (n - 1)			//把 n 的最后一个 1 去掉

2. GCD 和 LCM

GCD

性质:

gcd(a, b) = gcd(|a|, |b|);
gcd(a, b) = gcd(a, k * a + b);
gcd(k * a, k * b) = k * gcd(a, b);
gcd(a, b, c) = gcd(gcd(a, b), c);
若 gcd(a, b) = d, 则 gcd(a / d, b / d) = 1, 即 a / d 与 b / d 互素

库函数

__gcd(a, b);
gcd(a, b);	// C++17 引入

模板

辗转相除法
int gcd(int a, int b) 
{
	if(b > a) // 保证a是大数,b是小数
	{
		a ^= b;// 交换两数的值
		b ^= a;
		a ^= b;
	}
	while(b > 0) // 终止条件就是b == 0
	{
		int r = a % b;
		a = b;
		b = r;
	}
	return a;
}

int gcd(int a, int b)
{
	return b ? gcd(b, a % b) : a;
}
更相减损术
int gcd(int a, int b)
{
	while(a != b)
	{
		if(a > b)	a = a - b;
		else	b = b - a;
	}
	return a;
}

LCM

算术基本定理

任何大于 1 的自然数 n, 如果 n 不为质数,那么 n 可以唯一分解成有限个质数的乘积

库函数

lcm(a, b)	// C++17 引入

模板

int lcm(int a, int b)
{
	return a * gcd(a, b) / b;
}

裴蜀定理

定义

如果 ab 均为整数,则有整数 xy 使 a * x + b * y = gcd(a, b)

推论

整数 ab 互素当且仅当存在整数 xy ,使 a * x + b * y = 1

3. 异或空间线性基

// 不用高斯消元求线性基
const int M = 63;
  
// 数组p[]存储线性基, p[i] 表示最高位在第 i 位的元素
int p[M]; // 线性基
bool zero;

void insert(int x)
{
    for (int i = M; i >= 0; i--)
        if (x >> i == 1)   		// x 的最高位
            if (p[i] == 0) 		// p[i]还没有, 直接让 p[i] = x;
            {
                p[i] = x;
                return;
            }
            else 				// p[i] 已经有了, 逐个异或
                x ^= p[i];
    zero = true; 				// 有异或为 0 的组合
}

int qmax()
{
    int ans = 0;
    for (int i = M; i >= 0; i--)
        ans = max(ans, ans ^ p[i]);

    return ans;
}

int main()
{
    int x;
    int n;
    cin >> n;
    for (int i = 1; i <= n; i++)
        cin >> x, insert(x);
    cout << qmax() << endl;
}

4. 快速幂

\(a^n\) 的值

int fastPow(int a, int n)
{
    int res = 1;
    while(n)
    {
        if(n & 1)		res *= a;
        a *= a;
        n >>= 1;
    }
    return res;
}

\(a^n\) %mod 的值

int fastPow(int a, int n, int mod)
{
    int res = 1 % mod;
    a %= mod;
    while(n)
    {
        if(n & 1)		res = res * a % mod;
        a = a * a % mod;
        n >>= 1;
    }
    return res;
}

5. 模运算

加:(a + b) mod m = ((a mod m) + (b mod m)) mod m
减:(a - b) mod m = ((a mod m) - (b mod m)) mod m
乘:(a * b) mod m = ((a mod m) * (b mod m)) mod m

求 a * b % mod 的值

int mul(int a, int b, int mod)
{
    a = a % mod;
    b = b % mod;
    int res = 0;
    while (b > 0)
    {
        if (b & 1)		res = (res + a) % mod;
        a = (a + a) % mod;
        b >>= 1;
    }
    return res;
}

//a * b = (a * 2 * 2 * ... * 2) *( b / 2 / 2 / ...  / 2)
//b 若为奇数, 加上多的 a * 2

另一种解法:\(a*b\) %mod = \(a*b\) - \(\lfloor a*b/mod \rfloor\) * mod

int mul(int a, int b, int mod)
{
	a %= mod;
	b %= mod;
	int c = (ld)a * b / mod;
	int res = a * b - c * mod;
	if(res < 0)	res += mod;
	else if(res >= mod)	res -= mod;
	return res;
}

Barrett 模乘优化

1651. 锻炼 - AcWing题库
kactl/content/various/FastMod.h at main · kth-competitive-programming/kactl · GitHub
几种取模优化方法(译自 min-25 的博客) - 讨论 - LibreOJ (loj.ac)
巴雷特还原 - 维基百科,自由的百科全书 --- Barrett reduction - Wikipedia
AcWing 5579. 增加模数 : Barrett 模乘优化取模运算的性能测试对比 - AcWing

Barrett 模乘源码对于 M≥2 时都是适用的(分析源码原理不难得出,M=1 时会出现溢出情况从而无法正常使用)

#include <bits/stdc++.h>
using namespace std;

typedef unsigned long long ull;
typedef __uint128_t L;
struct FastMod 
{
    ull b, m;
    FastMod(ull b) : b(b), m(ull((L(1) << 64) / b)) {}
    ull reduce(ull a) {
        ull q = (ull)((L(m) * a) >> 64);
        ull r = a - q * b; // can be proven that 0 <= r < 2*b
        return r >= b ? r - b : r;
    }
};

FastMod F(2);

int main() {
    int M = 1000000007; F = FastMod(M);
    ull x = 10ULL*M+3; 
    cout << x << " " << F.reduce(x) << "\n"; // 10000000073 3
}

6. 欧拉函数

定义

n 是一个正整数,欧拉函数 \(\phi(n)=\sum_{i=1}^n{[gcd(i,n)=1]}\) 定义为不超过 n与 n 互素 的正整数的个数

定理一

pq互素 的正整数,那么 \(\phi(pq)=\phi(p)\phi(q)\)

定理二

n 为正整数,那么 \(n=\sum_{d|n}{\phi(d)}\) ,其中,d|n 表示 d 整除 n,上式表示对 n 的正因数 求和。例如,n=12, 那么 d 是 1,2,3,4,6,12,有 \(12=\phi(1)+\phi(2)+\phi(3)+\phi(4)+\phi(6)+\phi(12)\)n的正因数的欧拉函数之和等于 n

求欧拉函数的通解公式

欧拉定理

m 是一个正整数,a 是一个整数且 a 与 m 互素,即 gcd(a, m) = 1,则有 \(a^{\phi(m)}\equiv1(mod\;m)\)

定理三

\(n=p_1^{a_1}\times p_2^{a_2}\dots\times p_s^{a_s}\) 为整数 n 的 质幂因数分解,那么 \(\phi(n)=n(1-\frac{1}{p_1})(1-\frac{1}{p_2})\dots(1-\frac{1}{p_k})=n\prod_{i=1}^k(1-\frac{1}{p_i})\)

上述公式有以下两种特殊情况

(1)若 n 是素数,\(\phi(n)=n-1\)
(2)若 \(n=p^k\),p 是素数,有 \(\phi(n)=\phi(p^k)=p^k-p^{k-1}=p^{k-1}(p-1)=p^{k-1}\phi(p)\)

求单个欧拉函数
int euler(int n)
{
	int ans = n;
	for (int p = 2; p * p <= n; ++p)
	{
		if(n % p == 0)
		{
			ans = ans / p * (p - 1);
			while (n % p == 0)
				n /= p;
		}
	}
	if (n != 1)	ans = ans / n * (n - 1);
	return ans;
}

用线性筛 (欧拉筛) 求 1~n 内的所有欧拉函数

const int N = 50000; 

int vis[N];
int prime[N];
int phi[N];
int sum[N];

void get_phi()
{
	phi[1] = 1;
	int cnt = 0;
	for (int i = 2; i < N; i++)
	{
		if(!vis[i])
		{
			vis[i] = i;
			prime[cnt++] = i;
			phi[i] = i - 1;
		}
		for (int j = 0; j < cnt; j++)
		{
			if(i * prime[j] > N)	break;
			vis[i * prime[j]] = prime[j];

			if(i % prime[j] == 0)
			{
				phi[i * prime[j]] = phi[i] * prime[j];
				break;
			}
			phi[i * prime[j]] = phi[i] * phi[prime[j]];
		}
	}
}

int main()
{
	get_phi();
	sum[1] = 1;
	for (int i = 2; i <= N; i++)	sum[i] = sum[i - 1] + phi[i];
	int n;
	scanf("%d", &n);
	if(n == 1)	printf("0\n");
	else	printf("%d\n", 2 * sum[n - 1] + 1);
}

7. 矩阵的应用

矩阵乘法

//A:m * n		B: n * u
for(int i = 1; i <= m; i++)
	for(int j = 1; j <= u; j++)
		for(int k = 1; k <= n; k++)
			c[i][j] += a[i][k] * b[k][j];

矩阵快速幂

struct matrix
{
	int m[N][N]; 
	matrix() { memset(m, 0, sizeof(m)); }
};

matrix operator*(const matrix &a, const matrix &b)
{
    matrix c;
    memset(c.m, 0, sizeof(c.m));
    
    for (int i = 0; i < N; i++)
        for (int j = 0; j < N; j++)
            for (int k = 0; k < N; k++)
                // c.m[i][j] += a.m[i][k] * b.m[k][j];      //不取模
                c.m[i][j] = (c.m[i][j] + a.m[i][k] * b.m[k][j] % mod) % mod; // 取模
	return c;
}

matrix pow_matrix(matrix a, int n)
{
    matrix res;
    memset(res.m, 0, sizeof(res.m));

	// 初始化为单位矩阵
    for (int i = 0; i < N; i++) 	res.m[i][i] = 1;

    while (n)
    {
        if (n & 1)
            res = res * a;
        a = a * a;
        n >>= 1;
    }
    return res;
}

矩阵快速幂加速递推

3070 -- Fibonacci (poj.org)

#include<iostream>
#include<cstring>
using namespace std;
#define int long long
const int N = 2;
const int mod = 1e4;

struct matrix
{
    int m[N][N];
    matrix() { memset(m, 0, sizeof(m)); }
};

matrix operator*(const matrix &a, const matrix &b)
{
    matrix c;
    memset(c.m, 0, sizeof(c.m));
    for (int i = 0; i < N; i++)
        for (int j = 0; j < N; j++)
            for (int k = 0; k < N; k++)
                c.m[i][j] = (c.m[i][j] + a.m[i][k] * b.m[k][j]) % mod; // 取模
    return c;
}

matrix pow_matrix(matrix a, int n)
{
    matrix res;
    memset(res.m, 0, sizeof(res.m));
    
    for (int i = 0; i < N; i++) // 初始化为单位矩阵
        res.m[i][i] = 1;
        
    while (n)
    {
        if (n & 1)		res = res * a;
        a = a * a;
        n >>= 1;
    }
    return res;
}

signed main()
{
    int n;
    while (cin >> n && n != -1)
    {
        matrix a;
        a.m[0][0] = 1;
        a.m[0][1] = 1;
        a.m[1][0] = 1;
        matrix ans = pow_matrix(a, n);
        cout << ans.m[1][0] << endl;
    }
}

其他

【算法讲解】方程式配平法求线性递推方程转移矩阵_哔哩哔哩_bilibili 17 min

8. 整除分块(数论分块)

整除分块是为了解决一个整除的求和问题 \(\sum_{i=1}^n{\lfloor {\frac{n}{i}} \rfloor}\)

\(\lfloor {\frac{n}{i}} \rfloor\) 按相同值分块一共需要分为 \(2\sqrt{n}\)

int main()
{
	int n, L, R, ans = 0;
	cin >> n;
	for (L = 1; L <= n; L = R + 1)
	{
		R = n / (n / L);
		ans += (R - L + 1) * (n / L);
		cout << L << "-" << R << ":" << n / R << endl;
	}
	cout << ans << endl;
}
ull solve(ull n)
{
    ull ans = 0;
    ull r;

    for (ull l = 1; l <= n; l = r + 1)
    {
        ull s = n / l;                        
        r = n / s;                            
        ans += (l + r) * (r - l + 1) / 2 * s;
    }

    return ans;
}

int main()
{
    ull a,b;
    while((scanf("%llu%llu", &a, &b)!=EOF))
        cout<<sol(b)-sol(a-1)<<endl;
    
    return 0;
}

9. 素数

小素数的判定

试除法

前提:n<= \(10^{12}\)

bool is_prime(int n)
{
	if(n < 2 || (n !=2 && n % 2 ==0))	return false;
	for(int i = 3; i <= sqrt(n); i += 2)
		if(n % i == 0)	return false;
	return true;	
}

PI (x) 表示不超过整数 x 的素数的个数

素数定理:随着 x 的无限增长,PI (x)x / ln (x) 的比趋于 1

大素数的判定

费马小定理:设 n 是素数,a 是正整数且与 n 互素,那么就有 \(a^{n-1}\) 恒等于 1 (mod n)

二次探测定理:如果 p 是一个 奇素数,且 e>=1,则方程 \(x^2\) 恒等于 1 (mod \(p^e\)) 仅有两个解:x = 1x = -1。当 e = 1 时,方程 \(x^2\) 恒等于 1 (mod p) 仅有两个解 x = 1x = p - 1

素数筛

埃氏筛

int prime[N];
bool vis[N];

int E_sieve(int n)		// [2, n] 内的素数
{
	for(int i = 2; i <= sqrt(n); i++)
		if(!vis[i])
			for(int j = i * i; j <= n; j += i)	vis[j] = true;
			
	int k = 0;
	for(int i = 2; i <= n; i++)
		if(!vis[i])		prime[k++] = i;

	return k;
}

欧拉筛

int prime[N];
bool vis[N];

int euler_sieve(int n)	// [2, n] 内的素数
{
	int k = 0;
	for(int i = 2; i <= n; i++)
	{
		if(!vis[i])		prime[k++] = i;
		for(int j = 0; j < k; j++)
		{
			if(i * prime[j] > n)	break;
			vis[i * prime[j]] = true;
			if(i % prime[j] == 0)	break;
		}
	}
	return k;
}

质因数分解

算术基本定理:任何一个正整数 n 都可以唯一分解为有限个 素数 的乘积

欧拉筛求最小质因数

int prime[N];
int vis[N];		// 记录最小质因数

int euler_sieve(int n)	// [2, n] 内的素数
{
	int k = 0;
	for(int i = 2; i <= n; i++)
	{
		if(!vis[i])
		{
			vis[i] = i;
			prime[k++] = i;
		}
		for(int j = 0; j < k; j++)
		{
			if(i * prime[j] > n)	break;
			vis[i * prime[j]] = prime[j];
			if(i % prime[j] == 0)	break;
		}
	}
	return k;
}

试除法分解质因数

10. 高斯消元

#define eps 1e-9

int main()
{
    int n;
    cin >> n;
    vector<vector<double>> a(n + 1, vector<double>(n + 2));

    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= n + 1; j++)
            cin >> a[i][j];
  
    for (int i = 1; i <= n; i++)
    {
        int k = i;
        for (int j = i + 1; j <= n; j++)
            if (fabs(a[j][i]) > fabs(a[k][i]))	k = j;

        swap(a[i], a[k]);

        if (fabs(a[i][i]) < eps)
        {
            puts("No Solution");
            return 0;
        }

        for (int j = n + 1; j >= i; j--)	a[i][j] /= a[i][i];

        for (int j = 1; j <= n; j++)
        {
            if (j != i)
            {
                double temp = a[j][i] / a[i][i];
                for (int k = n + 1; k >= i; k--)
                    a[j][k] -= a[i][k] * temp;
            }
        }
    }

    for (int i = 1; i <= n; i++)
        printf("%.2lf\n", a[i][n + 1]);
}

11. 莫比乌斯函数与莫比乌斯反演

定义

莫比乌斯函数 \(u(n)\) 定义为 $$u(n)=\begin{cases}
1,;n=1\
{(-1)}^r,;n=p_1p_2\dots p_r,;其中;p_i;为不同的素数\
0,;其他
\end{cases}$$

定理

定理一

莫比乌斯函数的和函数在整数 \(n\) 处的值 \(F(n)=\sum_{d|n}u(d)\) ,满足 $$\sum_{d|n}u(d)=\begin{cases}
1,;n=1\
0,;n=1
\end{cases}$$

定理二

莫比乌斯反演公式。若 \(f\) 是算术函数,\(F\)\(f\) 的和函数,对任意正整数 \(n\) ,满足 \(F(n)=\sum_{d|n}f(d)\) ,则有 \(f(n)=\sum_{d|n}u(d)F(\frac{n}{d})\)

定理三

\(f\) 是算术函数,它的和函数为 \(F(n)=\sum_{d|n}f(d)\) 。如果 \(F\) 是积性函数,则 \(f\) 也是积性函数

12. 同余

13. 威尔逊定理

若 p 为素数,则 p 可以整除 (p - 1) ! + 1

1. ((p - 1) ! + 1) mod p = 0
2. (p - 1) ! mod p = p - 1
3. (p - 1) ! = pq - 1		q 为整数
4. 用同余表示为 (p - 1) ! 恒等于 -1 (mod p)

14. 0/1 分数规划

15. 杜教筛

16. 狄利克雷卷积

定义

fg 是算术函数,记 fg狄利克雷卷积f * g,定义为 \((f*g)(n)=\sum_{d|n} f(d)\;g(\frac{n}{d})\)

性质

  1. 交换律 \(f*g=g*f\)
  2. 结合律 \((f*g)*h=f*(g*h)\)
  3. 分配律 \(f*(g+h)=(f*g)+(f*h)\)
  4. 元函数的定义为 $$\epsilon(n)=\lfloor {\frac{1}{n}} \rfloor=\begin{cases}
    1, & n=1 \
    0, & n>1
    \end{cases}$$ 对于任何 \(f\) , 有 \(\epsilon*f=f*\epsilon=f\)
  5. 两个积性函数的狄利克雷卷积仍然是积性函数

17. 积性函数

18. 线性丢番图方程

组合数学

1. 二项式定理和杨辉三角

二项式定理

\[(a+b)^n=\sum_{r=0}^nC_n^ra^rb^{n-r}=\sum_{r=0}^nC_n^rb^ra^{n-r} \]

  • 计算二项式系数
  1. 递推公式 \(C_n^r=C_{n-1}^r+C_{n-1}^{r-1}\)
  2. 用逆计算

杨辉三角

\((1+x)^n\) 的系数

计算杨辉三角

int a[21][21];
int main()
{
	int n;	cin >> n;
	for (int i = 1; i <= n; i++)	a[i][1] = a[i][i] = 1;	// 赋初值
	for (int i = 1; i <= n; i++)
		for (int j = 2; j < i; j++)
			a[i][j] = a[i - 1][j] + a[i - 1][j - 1];	// 递推二项式求系数

	for (int i = 1; i <= n; i++)
	{
		for (int j = 1; j <= i; j++)
			cout << a[i][j] << " ";
		cout << endl;		
	}
}

计算二项式系数

P 1313 [NOIP 2011 提高组] 计算系数 - 洛谷 | 计算机科学教育新生态

递推公式
const int N = 1005;
const int mod = 10007;
int c[N][N];

int fastPow(int a, int n)
{
    int res = 1 % mod;
    a %= mod;
    while (n)
    {
        if (n & 1)	res = res * a % mod;
        a = a * a % mod;
        n >>= 1;
    }
    return res;
}

int dfs(int n, int m) // 递推公式求二项式系数
{
    if (!m)			return c[n][m] = true;
    if (m == 1)		return c[n][m] = n;
    if (c[n][m])	return c[n][m];
    if (n - m < m)	m = n - m;
    return c[n][m] = (dfs(n - 1, m) + dfs(n - 1, m - 1)) % mod;
}

int main()
{
    int a, b, k, n, m;
    cin >> a >> b >> k >> n >> m;
    c[1][0] = c[1][1] = 1;
    int ans = 1;
    ans *= (fastPow(a, n) * fastPow(b, m)) % mod;
    ans *= dfs(k, n) % mod;
    cout << ans % mod << endl;
}
const int N = 10005;
const int mod = 10007;
int fac[N], inv[N]; // 预计算阶乘和逆

int fastPow(int a, int n)
{
    int res = 1 % mod;
    a %= mod;
    while (n)
    {
        if (n & 1)	res = res * a % mod;
        a = a * a % mod;
        n >>= 1;
    }
    return res;
}

int C(int n, int m) // 计算组合数,用到除法取模的逆
{
    return (fac[n] * inv[m] % mod * inv[n - m] % mod) % mod;
}

int main()
{
    int a, b, k, n, m, ans;	cin >> a >> b >> k >> n >> m;
    fac[0] = 1;
    for (int i = 1; i <= n + m; i++)
    {
        fac[i] = (fac[i - 1] * i) % mod;   // 预计算阶乘,要取模
        inv[i] = fastPow(fac[i], mod - 2); // 用费马小定理预计算逆
    }
    ans = (fastPow(a, n) % mod * fastPow(b, m) % mod * C(k, n) % mod) % mod;
    cout << ans << endl;
}

2. 容斥原理

简单形式

\(A\)\(B\) 是分别具有性质 \(P_1\)\(P_2\) 的有限集,则有

\[\mid A\;\cup\;B\mid\;=\;\mid A \mid +\mid B \mid -\mid A \;\cup\;B\mid \]

定义

集合 \(S\) 的子集 \(A_1\) 有性质 \(P_1\)\(A_2\) 有性质 \(P_2\)\(\cdots\)\(A_n\) 有性质 \(P_n\) ,有以下两种定义:

  1. 集合 \(S\) 中不具有性质 \(P_1\)\(P_2\)\(\cdots\)\(P_n\) 的对象个数为

\[\mid \overline{A_1}\;\cap\;\overline{A_2}\;\cap\;\cdots\;\cap\;\overline{A_n} \mid\;=\;\mid S \mid -\sum \mid A_i \mid + \sum \mid \overline{A_i} \;\cap\;\overline{A_j} \mid - \sum \mid \overline{A_i} \;\cap\; \overline{A_j} \;\cap\; \overline{A_k} \mid + \;\cdots\; + (-1)^n \mid \overline{A_1} \;\cap\; \overline{A_2} \;\cap\; \cdots \;\cap\; \overline{A_n} \mid \]

  1. 集合 \(S\) 中至少具有性质 \(P_1\)\(P_2\) , \(\cdots\)\(P_n\) 之一的对象个数为

\[\mid A_1 \;\cup\; A_2 \;\cup\; \cdots \;\cup A_n \mid \;= \; \sum \mid A_i \mid - \sum \mid A_i \;\cap\; A_j \mid + \mid A_i \;\cap\; A_j \;\cap\; A_k \mid + \;\cdots\; + (-1)^{n+1} \mid A_1 \;\cap\; A_2 \;\cap\; \cdots \;\cap A_n \mid \]

3. 卢卡斯定理

适用于计算组合数取模,即求 \(C_n^r \;mod\; m\) ,其中 \(m\) 为素数

定理

对于非负整数 \(n、r\) 和素数 \(m\) ,有

\[C_n^r\;\equiv\;\prod_{i=0}^kC_{n_i}^{r_i}\;(mod\;m) \]

或者写成

\[C_n^r\;mod\;m\;=\;\prod_{i=0}^kC_{n_i}^{r_i}\;mod\;m \]

其中,\(n=n_k*m^k+\cdots+n_1*m+n_0*m^0\)\(r=r_k*m^k+\cdots+r_1*m+r_0*m^0\)\(n\)\(r\)\(m\) 进制展开

另一种表达:

\[ C_n^r\;\equiv\;C_{n\;mod\;m}^{r\;mod\;m}\;*\;C_{n/m}^{r/m}\;(mod\;m) \]

P3807 【模板】卢卡斯定理/Lucas 定理 - 洛谷 | 计算机科学教育新生态

#define int long long
const int N = 100010;
int fac[N]; // 预计算阶乘,取模

int fastPow(int a, int n, int mod)
{
    int res = 1;
    a %= mod;
    while (n)
    {
        if (n & 1)	res = res * a % mod;
        a = a * a % mod;
        n >>= 1;
    }
    return res;
}

int inverse(int a, int m) // 用费马小定理计算逆
{
    return fastPow(fac[a], m - 2, m);
}

int C(int n, int r, int m) // 用逆计算 C(n mod m, r mod m) mod m
{
    if (r > n)	return 0;
    return ((fac[n] * inverse(r, m)) % m * inverse(n - r, m) % m);
}

int Lucas(int n, int r, int m) // 用递归计算 C(n, r) mod m
{
    if (r == 0)	return 1;
    return C(n % m, r % m, m) * Lucas(n / m, r / m, m) % m; // 分两部分计算
}

signed main()
{
    int T;	cin >> T;
    while (T--)
    {
        int a, b, m;
        cin >> a >> b >> m;
        fac[0] = 1;
        for (int i = 1; i <= m; i++)
            fac[i] = (fac[i - 1] * i) % m;	// 预计算阶乘,取模
        cout << Lucas(a + b, a, m) << endl;
    }
}

4. 鸽巢原理(抽屉原理)

第一抽屉原理

  1. 把多于 \(n\) 个的物体放到 \(n\) 个抽屉里,则至少有一个抽屉里的东西不少于两件
  2. 把多于 \(m*n+1(n不为0)\) 个的物体放到 \(n\) 个抽屉里,则至少有一个抽屉里有不少于 \((m+1)\) 的物体
  3. 把无数还多件物体放入 \(n\) 个抽屉,则至少有一个抽屉里有无数个物体

第二抽屉原理

\((m*n-1)\) 个物体放入 \(n\) 个抽屉中,其中必有一个抽屉中至多有 \((m—1)\) 个物体 (例如,将 \(3×5-1=14\) 个物体放入 \(5\) 个抽屉中,则必定有一个抽屉中的物体数少于等于 \(3-1=2\))

加强版

\(q_1,\;q_2,\; q_3,\; \cdots,\; q_n\) 为正整数,如果将 \(q_1+q_2+q_3+\cdots+q_n-n+1\) 个物体放入 \(n\) 个盒子,那么,或者第一个盒子至少含有 \(q_1\) 个物体,或者第二个盒子至少含有 \(q_2\) 个物体,\(\cdots\),或者第 \(n\) 个盒子至少含有 \(q_n\) 个物体

Ramsey 定理

一个简单例子

\(6\) 个或更多人中,或者有 \(3\) 个人,他们中的每两个人都互相认识:或者有 \(3\) 个人,他们中的每两个人都彼此不认识

5. Burnside 定理和 Polya 计数

6. 公平组合游戏(博弈论)

7. Catalan 数和 Stirling 数

8. 母函数

计算几何

1. 圆

2. 二位几何

3. 三维几何

posted @ 2025-07-29 22:39  Aurora_333  阅读(7)  评论(0)    收藏  举报