威尔逊定理+裴蜀定理+求线性同余的方法
威尔逊定理
\(定义: (p-1)! \ \equiv\ -1 \ (mod \ p)是p为质数的充分必要条件\)
\(推论:若p是质数, 则 (p-1)! \ + \ 1\ \equiv\ 0 \ (mod \ p);
若p是大于4的合数,则 (p-1)! \ \ \equiv\ 0 \ (mod \ p)\)
例题:https://acm.hdu.edu.cn/showproblem.php?pid=2973
题意:
\(给定n, 求S_n = \sum_{k=1}^{n} \left[ \frac{(3k+6)! + 1}{3k+7} - \left[ \frac{(3k+6)!}{3k+7} \right] \right]\)
\(令p = 3k + 7,则原式化为:S_n = \sum_{k=1}^{n} \left[ \frac{(p-1)! + 1}{p} - \left[ \frac{(p-1)!}{p} \right] \right]\)
\(那么当p为质数的时候, \frac{(p-1)! + 1}{p} 值为整数,所以\frac{(p-1)!}{p}值比前者小1;\) \(当p为合数的时候,\frac{(p-1)!}{p}值为整数,同时\frac{(p-1)! + 1}{p}值也为整数,所以两者相减值为0\)
\(所以S_n的值为[1, n]中质数的个数,只需要通过筛法求出1~n中质数的个数即可求解\)
#include <bits/stdc++.h>
#define PRINT_PI(presision, value) std::cout << std::fixed << std::setprecision(presision) << (value) << std::endl
const int N = 3000007;
bool st[N];
int p[N];
int s[N];
void getPrimes(int n) {
for (int i = 2; i < n; i ++) {
if (!st[i]) {
// i是质数
if ((i-7) % 3 == 0) {
// i满足3k + 7形式
p[(i-7) / 3] = 1;
}
for (int j = i+i; j < n; j += i) st[j] = true;
}
}
}
int main()
{
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
int t = 1;
std::cin >> t;
getPrimes(N);
for (int i = 2; i <= N; i ++) s[i] = s[i-1] + p[i];
while (t --) {
int n;
std::cin >> n;
std::cout << s[n] << "\n";
}
return 0;
}
裴蜀定理
\(定义:一定存在整数x, y,满足ax + by = gcd(a, b)\)
\(推广1:一定存在整数x, y,满足ax + by = gcd(a, b) * n\)
\(推广2:一定存在整数x_1, x_2, ……,x_n满足\sum_{i=1}^{n}A_iX_i = gcd(A_1, A_2,…,A_n);\)
\(求gcd时候,需要带入A_i的绝对值,否则可能回出现负数\)
https://www.luogu.com.cn/problem/P4549
#include <bits/stdc++.h>
int main()
{
int n;
std::cin >> n;
std::vector<int> a(n+1);
std::cin >> a[1];
int res = std::abs(a[1]);
for (int i = 2; i <= n; i ++) {
std::cin >> a[i];
res = std::__gcd(res, std::abs(a[i]));
}
std::cout << res << "\n";
}
求线性同余方程
\(题意:给定整数a, b, m。求解:ax \equiv\ b \ (mod \ m)\)
\(步骤:1、把线性同余方程化为不定方程\)
\(由ax \equiv\ b \ (mod \ m) => ax = m(-y) + b => ax + my = b
由裴蜀定理:gcd(a, m) | b时有解,即b \% gcd(a, m) = 0\)
\(2、用扩展欧几里得算法求解:ax + my = gcd(a, m)时的解
最后把x 乘以 \frac{b}{gcd(a, m)}得到原方程的解\)
https://www.luogu.com.cn/problem/P1082
#include <bits/stdc++.h>
using i64 = long long;
i64 exgcd(i64 a, i64 b, i64 &x, i64 &y) {
if (b == 0) {
x = 1, y = 0;
return a;
}
i64 x1, y1;
i64 d = exgcd(b, a % b, x1, y1);
x = y1, y = x1 - a / b * y1;
return d;
}
int main()
{
i64 a, b;
std::cin >> a >> b;
i64 x, y;
i64 d = exgcd(a, b, x, y);
std::cout << (x + b) % b << "\n";
return 0;
}
求逆元的方法(总结)
给定互质的两个整数a, m。求a在模m意义下的逆元
1、m为质数时,可用快速幂+费马小定理求解
由\(a^{m-1} \equiv\ 1 \ ( mod \ m) => a * a ^ {m-2} \equiv\ 1 \ (mod \ m),a ^ {m-2}即为逆元\)
2、m为任意正整数时,用扩展欧几里得算法求解
\(即求ax \equiv\ 1\ (mod \ m)的解,=> ax + my = 1,其中a,m互质,所以gcd(a, m) | 1,所以ax + my = 1有解,用欧几里得算法求出x的值即为逆元\)
本文来自博客园,作者:来杯whiskey,转载请注明原文链接:https://www.cnblogs.com/zj-cnbolgs/p/18887889