[关闭]
@Dmaxiya 2019-02-14T16:13:02.000000Z 字数 4265 阅读 1245

数论

板子


快速幂

  1. const LL MOD = 1000000007;
  2. // 求res 的n 次方对MOD 取模
  3. LL fast_pow(LL res, LL n) {
  4. LL ans;
  5. for(ans = 1; n != 0; n >>= 1) {
  6. if(n % 2 == 1) ans = (ans * res) % MOD;
  7. res = (res * res) % MOD;
  8. }
  9. return ans;
  10. }

逆元预处理 + Lucas 定理

  1. const LL MOD = 1e9 + 7;
  2. const int maxn = 1e6 + 100;
  3. LL inv[maxn], pro[maxn], invpro[maxn];
  4. // maxn 为所求数字上界,当n 和m 大于MOD 时,需要用到Lucas 函数
  5. // 否则只要直接get_C 函数即可
  6. void Prepare_C() {
  7. inv[1] = 1;
  8. for(int i = 2; i < maxn; ++i) {
  9. inv[i] = (LL)(MOD - MOD / i) * inv[MOD % i] % MOD;
  10. }
  11. pro[0] = invpro[0] = 1;
  12. for(int i = 1; i < maxn; ++i) {
  13. pro[i] = pro[i - 1] * i % MOD;
  14. invpro[i] = invpro[i - 1] * inv[i] % MOD;
  15. }
  16. }
  17. LL get_C(int n, int m) {
  18. if(n < m) {
  19. return 0;
  20. }
  21. return pro[n] * invpro[m] % MOD * invpro[n - m] % MOD;
  22. }
  23. LL Lucas(LL n, LL m) {
  24. if(n < MOD && m < MOD) {
  25. return get_C(n, m);
  26. }
  27. LL tmp = get_C(n % MOD, m % MOD);
  28. if(tmp == 0) {
  29. return 0;
  30. }
  31. return tmp * Lucas(n / MOD, m / MOD) % MOD;
  32. }

埃氏素数(HDU 1164

  1. const int maxn = 100000 + 100;
  2. int n, cnt;
  3. int prime[maxn];
  4. bool vis[maxn];
  5. void Prime() {
  6. for(int i = 2; i < maxn; ++i) {
  7. if(!vis[i]) {
  8. prime[cnt++] = i;
  9. for(int j = i; j < maxn / i; ++j) {
  10. vis[i * j] = true;
  11. }
  12. }
  13. }
  14. }

欧拉筛素数/欧拉函数/莫比乌斯函数打表(HDU 2841

  1. const int maxn = 100000 + 100;
  2. int cnt;
  3. int prime[maxn], mu[maxn], phi[maxn];
  4. bool vis[maxn];
  5. // prime 下标范围为 [0, cnt)
  6. // phi 为欧拉函数,mu 为莫比乌斯函数
  7. // vis[i] 为 false 表示 i 是质数
  8. // 调用时 n 需小于 maxn
  9. void Prime(int n) {
  10. mu[1] = 1;
  11. phi[1] = 1;
  12. for(int i = 2; i <= n; ++i) {
  13. if(!vis[i]) {
  14. prime[cnt++] = i;
  15. mu[i] = -1;
  16. phi[i] = i - 1;
  17. }
  18. for(int j = 0; j < cnt && i <= n / prime[j]; ++j) {
  19. int k = i * prime[j];
  20. vis[k] = true;
  21. if(i % prime[j] == 0) {
  22. mu[k] = 0;
  23. phi[k] = phi[i] * prime[j];
  24. break;
  25. } else {
  26. mu[k] = -mu[i];
  27. phi[k] = phi[i] * (prime[j] - 1);
  28. }
  29. }
  30. }
  31. }

分解质因数

  1. void get_fac(LL n, vector<pair<LL, int> > &p) {
  2. for(int i = 0; i < cnt && prime[i] <= n / prime[i]; ++i) {
  3. if(n % prime[i] == 0) {
  4. p.push_back(make_pair(prime[i], 0));
  5. while(n % prime[i] == 0) {
  6. ++p.back().second;
  7. n /= prime[i];
  8. }
  9. }
  10. }
  11. if(n != 1) {
  12. p.push_back(make_pair(n, 1));
  13. }
  14. }

gcd(n, m) = d 的对数(HDU 1695

  1. // 求从 1 到 n 和 1 到 m 之间有多少个有序对 (a, b) 满足 gcd(a, b) = d
  2. // 时间复杂度 O(sqrt(min(n, m) / d))
  3. // sum 为莫比乌斯函数前缀和
  4. LL F(int n, int m, int d) {
  5. if(n > m) {
  6. swap(n, m);
  7. }
  8. LL ret = 0;
  9. n /= d;
  10. m /= d;
  11. int last = 1;
  12. for(int i = 1; i <= n; i = last + 1) {
  13. last = min(n / (n / i), m / (m / i));
  14. ret += (LL)(sum[last] - sum[i - 1]) * (n / i) * (m / i);
  15. }
  16. return ret;
  17. }

√n求解欧拉函数

  1. int euler(int n) {
  2. if(n == 1) return 1;
  3. int ret = n;
  4. for(int j = 0; j < cnt && prime[j] * prime[j] <= n; ++j) {
  5. if(n % prime[j] == 0) {
  6. ret = ret / prime[j] * (prime[j] - 1);
  7. while(n % prime[j] == 0) n /= prime[j];
  8. }
  9. }
  10. if(n > 1) ret = ret / n * (n - 1);
  11. return ret;
  12. }

矩阵快速幂

  1. const int matrix_size = 10;
  2. const int MOD = 1000000007;
  3. int add(int a, int b) {
  4. a += b;
  5. if(a >= MOD) {
  6. return a - MOD;
  7. }
  8. return a;
  9. }
  10. struct Matrix {
  11. int size;
  12. int num[matrix_size][matrix_size];
  13. void operator=(const Matrix &m) {
  14. for(int i = 0; i < size; ++i) {
  15. memcpy(num[i], m.num[i], sizeof(int) * size);
  16. }
  17. }
  18. void Init() {
  19. for(int i = 0; i < size; ++i) {
  20. memset(num[i], 0, sizeof(int) * size);
  21. num[i][i] = 1;
  22. }
  23. }
  24. void Set(int s) {
  25. size = s;
  26. // codes...
  27. }
  28. void operator*=(const Matrix &m) {
  29. static Matrix ans;
  30. ans.size = size;
  31. for(int i = 0; i < size; ++i) {
  32. for(int j = 0; j < size; ++j) {
  33. ans.num[i][j] = 0;
  34. for(int k = 0; k < size; ++k) {
  35. ans.num[i][j] = add(ans.num[i][j], (LL)num[i][k] * m.num[k][j] % MOD);
  36. }
  37. }
  38. }
  39. (*this) = ans;
  40. }
  41. void fast_pow(LL n) {
  42. static Matrix ans;
  43. ans.size = size;
  44. for(ans.Init(); n != 0; n >>= 1) {
  45. if((n & 1) == 1) {
  46. ans *= (*this);
  47. }
  48. (*this) *= (*this);
  49. }
  50. (*this) = ans;
  51. }
  52. };

exgcd(cal 函数求ax + by = c 的最小非负整数解)

  1. void exgcd(LL a, LL b, LL &d, LL &x, LL &y) {
  2. if(b == 0) {
  3. d = a;
  4. x = 1;
  5. y = 0;
  6. } else {
  7. exgcd(b, a % b, d, y, x);
  8. y -= x * (a / b);
  9. }
  10. }
  11. void cal(LL a, LL b, LL c, LL &x, LL &y) {
  12. LL gcd;
  13. exgcd(a, b, gcd, x, y);
  14. if(c % gcd != 0) {
  15. x = -1;
  16. return ;
  17. }
  18. x *= c / gcd;
  19. LL mod = abs(b / gcd);
  20. x = (x % mod + mod) % mod;
  21. y = (c - a * x) / b;
  22. }

中国剩余定理

  1. // 下标范围为 [0, len)
  2. LL CRT(LL *r, LL *m, int len) { // r Remain m MOD
  3. LL M = m[0];
  4. LL ret = r[0];
  5. LL d, x, y;
  6. for(int i = 1; i < len; ++i) {
  7. exgcd(M, m[i], d, x, y);
  8. if((r[i] - ret) % d) {
  9. return -1; // 判断是否有解,无解返回 -1
  10. }
  11. x = (r[i] - ret) / d * x % (m[i] / d);
  12. ret += x * M;
  13. M = M / d * m[i];
  14. ret %= M;
  15. }
  16. ret = (ret + M) % M;
  17. return ret == 0? M: ret;
  18. }

数位dp

  1. int a[100];
  2. LL dp[20][2];
  3. LL dfs(int pos, int stat, bool limit) {
  4. if(pos == -1) {
  5. return stat;
  6. }
  7. if(!limit && dp[pos][stat] != -1) {
  8. return dp[pos][stat];
  9. }
  10. int up = limit? a[pos]: 9;
  11. LL ans = 0;
  12. for(int i = 0; i <= up; ++i) {
  13. ans += dfs(pos - 1, stat | (i == 6? 1: 0), limit && i == a[pos]);
  14. }
  15. if(!limit) {
  16. dp[pos][stat] = ans;
  17. }
  18. return ans;
  19. }
  20. LL solve(LL x) {
  21. int pos = 0;
  22. while(x != 0) {
  23. a[pos++] = x % 10;
  24. x /= 10;
  25. }
  26. return dfs(pos - 1, 0, true);
  27. }

反素数

  1. // depth 表示搜索到第 depth 个素数,素数下标范围为 [0, cnt),Count 为约数个数,up 为下一个素数指数最大值+1,ans 为 n 以最大反素数约数个数
  2. void dfs(int depth, LL Count, LL Num, int up) {
  3. ans = max(ans, Count);
  4. if(depth == cnt || Num > n / prime[depth]) {
  5. return ;
  6. }
  7. for(int i = 1; i < up && Num <= n / prime[depth]; ++i) {
  8. Num *= prime[depth];
  9. dfs(depth + 1, Count * (i + 1), Num, i + 1);
  10. }
  11. }

Catalan 数

令:,则 数满足递推式:


其通项为:

Catalan 数相关结论

个数的出栈、入栈方案数
对括号的匹配方案数
个节点构成的二叉树种数
圆上 个点,两两连线不相交的情况数
一个 边形,分割成多个三角形的方案数

直角三角形三边长为整数的可能斜边长

分解质因数后,统计其质因数对 取模等于 的个数,若个数大于 ,则满足条件。

斯特林近似

斯特林近似用于求解 的近似值:

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注