数学知识

97 阅读1分钟

本文已参与[新人创作礼]活动,一起开启掘金创作者之路。

数学知识对于算法竞赛也很重要,平常比赛时经常会用到很多的数学知识。;

Lucas定理 若p是质数,则对于任意整数 1 <= m <= n,有: C(n, m) = C(n % p, m % p) * C(n / p, m / p) (mod p)

int qmi(int a, int k, int p) // 快速幂模板 { int res = 1 % p; while (k) { if (k & 1) res = (LL)res * a % p; a = (LL)a * a % p; k >>= 1; } return res; }

int C(int a, int b, int p) // 通过定理求组合数C(a, b) { if (a < b) return 0;

LL x = 1, y = 1;  // x是分子,y是分母
for (int i = a, j = 1; j <= b; i --, j ++ )
{
    x = (LL)x * i % p;
    y = (LL) y * j % p;
}

return x * (LL)qmi(y, p - 2, p) % p;

}

int lucas(LL a, LL b, int p) { if (a < p && b < p) return C(a, b, p); return (LL)C(a % p, b % p, p) * lucas(a / p, b / p, p) % p; } 分解质因数法求组合数 当我们需要求出组合数的真实值,而非对某个数的余数时,分解质因数的方式比较好用: 1. 筛法求出范围内的所有质数 2. 通过 C(a, b) = a! / b! / (a - b)! 这个公式求出每个质因子的次数。 n! 中p的次数是 n / p + n / p^2 + n / p^3 + ... 3. 用高精度乘法将所有质因子相乘

int primes[N], cnt; // 存储所有质数 int sum[N]; // 存储每个质数的次数 bool st[N]; // 存储每个数是否已被筛掉

void get_primes(int n) // 线性筛法求素数 { for (int i = 2; i <= n; i ++ ) { if (!st[i]) primes[cnt ++ ] = i; for (int j = 0; primes[j] <= n / i; j ++ ) { st[primes[j] * i] = true; if (i % primes[j] == 0) break; } } }

int get(int n, int p) // 求n!中的次数 { int res = 0; while (n) { res += n / p; n /= p; } return res; }

vector mul(vector a, int b) // 高精度乘低精度模板 { vector c; int t = 0; for (int i = 0; i < a.size(); i ++ ) { t += a[i] * b; c.push_back(t % 10); t /= 10; }

while (t)
{
    c.push_back(t % 10);
    t /= 10;
}

return c;

}

get_primes(a); // 预处理范围内的所有质数

for (int i = 0; i < cnt; i ++ ) // 求每个质因数的次数 { int p = primes[i]; sum[i] = get(a, p) - get(b, p) - get(a - b, p); }

vector res; res.push_back(1);

for (int i = 0; i < cnt; i ++ ) // 用高精度乘法将所有质因子相乘 for (int j = 0; j < sum[i]; j ++ ) res = mul(res, primes[i]);