数论知识啊
同余
如果a, b除以相同的除数m并且得到的余数相同,就称整数a和b模m同余,记作$a \equiv b \pmod{m} 。准确地说,如果 。 准确地说,如果 。准确地说,如果a=b+km 的话, 的话, 的话, a ≡ b ( m o d m ) a \equiv b \pmod{m} a≡b(modm)例如 23 ≡ 65 ( m o d 7 ) 23 \equiv 65 \pmod{7} 23≡65(mod7)
互质
两个整数a,b的最大公约数是1( g c d ( a , b ) = 1 gcd(a,b)=1 gcd(a,b)=1),则整数a,b互质。
欧拉函数
欧拉函数通常用符号 φ ( n ) \varphi(n) φ(n) 表示。
φ ( n ) \varphi(n) φ(n) 表示:小于n的正整数中与n互质的数的个数,其中 φ ( 1 ) = 1 \varphi(1)=1 φ(1)=1。
若 n = p ∗ q n=p*q n=p∗q,则 φ ( n ) = ( p − 1 ) ( q − 1 ) \varphi(n)=(p-1)(q-1) φ(n)=(p−1)(q−1) 。
基本求法
#include <cstdio>
#include <iostream>using namespace std;int phi(int n){int ans = n;for(int i = 2; i * i <= n; i++) {if(n % i == 0){ans = ans - ans / i;while (n % i == 0) n /= i;}}if(n > 1) ans = ans - ans / n;return ans;
}int main() {int n;while (~scanf("%d", &n), n) {printf("%d\n", phi(n));}return 0;
}
用线性筛求欧拉函数
#include <cstdio>
#include <iostream>using namespace std;
const int maxn=1000;
int prime[maxn], phi[maxn];
bool notprime[maxn];void getphi(){phi[1] = 1;notprime[1] = 1;prime[0] = 0;for(int i = 2; i <= maxn; i++) {if(!notprime[i]) {prime[++prime[0]] = i;phi[i] = i-1;}for(int j = 1; j <= prime[0] && i * prime[j] <= maxn; j++){notprime[i * prime[j]] = 1;if (i % prime[j] == 0) {phi[i * prime[j]] = phi[i] * prime[j];break;}else phi[i * prime[j]] = phi[i] * (prime[j] - 1);}}
}
int main() {getphi();for(int i = 1; i <= 100; i++){printf("%d %d\n", i, phi[i]);}return 0;
}
欧拉定理
对于任何正整数 n 和整数 a,如果 a 和 n 互质(即它们的最大公因数是1),则有:
a φ ( n ) ≡ 1 ( m o d n ) a^{\varphi(n) } \equiv 1\pmod{n} aφ(n)≡1(modn)
其中,φ(n) 是欧拉函数,它表示小于或等于 n 的正整数中与 n 互质的数的个数。
费马小定理
如果 p 是一个素数,而 a 是不可被 p 整除的整数,那么:
a p − 1 ≡ 1 ( m o d p ) a^{p-1} \equiv 1\pmod{p} ap−1≡1(modp)
这个定理的条件是 a 不能被 p 整除,所以当 a 和 p 互质时,费马小定理就成立。
扩展欧几里得定理
裴蜀定理
裴蜀定理(Bézout’s Identity),也称为贝祖等式,是一个数论中的重要定理,它表明对于任何两个整数 a 和 b 的最大公约数(最大公因数),存在整数 x 和 y,使得它们可以表示为:
a ∗ x + b ∗ y = g c d ( a , b ) a * x + b * y = gcd(a, b) a∗x+b∗y=gcd(a,b)
裴蜀定理的一个重要结论是,如果 a 和 b 的最大公约数是 1(即 a 和 b 互质),那么存在整数 x 和 y,使得:
a ∗ x + b ∗ y = 1 a * x + b * y = 1 a∗x+b∗y=1
扩展欧几里得定理的内容
对于任何整数 a 和 b,存在整数 x 和 y,使得它们的最大公约数 d = gcd(a, b) 可以表示为:
a ∗ x + b ∗ y = d a * x + b * y = d a∗x+b∗y=d
简单推导
-
如果 a = 0,那么 a 和 b 的最大公约数就是 b,此时等式可以表示为:
0 ∗ x + b ∗ y = b 0 * x + b * y = b 0∗x+b∗y=b
这显然成立,因为 b * y = b,可以取 x = 0 和 y = 1。
-
一般情况下, 我们考虑 a 不等于 0 的情况
a x + b y = g c d ( a , b ) a x + b y = gcd(a,b) ax+by=gcd(a,b)
而 g c d ( a , b ) = g c d ( b , a % b ) gcd(a,b)=gcd(b,a \% b) gcd(a,b)=gcd(b,a%b)
b x 1 + ( a % b ) y 1 = g c d ( b , a % b ) bx_{1} + (a\%b)y_{1} = gcd(b, a\%b ) bx1+(a%b)y1=gcd(b,a%b)
而 a % b = a − k b = a − [ a b ] b a \% b = a - kb = a - \left [ \frac{a}{b} \right ] b a%b=a−kb=a−[ba]b
a x + b y = b x 1 + ( a − [ a b ] b ) y 1 ax + by = bx_{1} + (a - \left [ \frac{a}{b} \right ] b)y_{1} ax+by=bx1+(a−[ba]b)y1
a x + b y = b x 1 + a y 1 − [ a b ] b y 1 ax + by = bx_{1} + ay_{1} - \left [ \frac{a}{b} \right ] by_{1} ax+by=bx1+ay1−[ba]by1
a x + b y = a y 1 + b ( x 1 − [ a b ] y 1 ) ax + by = ay_{1} + b(x_{1} - \left [ \frac{a}{b} \right ] y_{1}) ax+by=ay1+b(x1−[ba]y1)
所以 x = y 1 , y = x 1 − [ a b ] y 1 x=y_{1} , y=x_{1}-\left [ \frac{a}{b} \right ] y_{1} x=y1,y=x1−[ba]y1
代码实现
ll exgcd(ll a, ll b, ll &x, ll &y){if(b == 0){x=1, y=0;return a;}ll d = exgcd(b, a%b, x, y);ll t = x;x = y;y = t - a / b * y;return d;
}
乘法逆元
对于一个整数 a 和一个正整数 n,a 在模 n 下的乘法逆元是另一个整数 x,使得:
a x ≡ 1 ( m o d n ) ax \equiv 1 \pmod{n} ax≡1(modn)
这意味着 a 与 x 的乘积模 n 后等于 1。如果存在这样的 x,那么 a 在模 n 下就有乘法逆元。
乘法逆元的存在性取决于 a 和 n 之间的关系。如果 a 与 n 互质(它们的最大公约数是1),则 a 在模 n 下一定有乘法逆元。
快速幂
ll qpow(ll a, ll b, ll mod) {ll ans = 1;while (b) {if (b & 1) ans = ans * a % mod;b >>= 1;a = a * a % mod;}return ans;
}
快速乘
ll qmul(ll a, ll b, ll mod){ll ans = 0;while (b) {if(b & 1){ans = (ans + a) % mod;}a = (a + a) % mod;b >>= 1;}return ans;
}
质因子分解(试除法)
#include <cstdio>
#include <iostream>
#include <vector>using namespace std;struct fac{int p, cnt;fac(){}fac(int pp, int cntt) : p(pp), cnt(cntt){}
}; vector<fac> divide(int n){vector<fac> a;for (int i = 2; i * i <= n; i++) {if (n % i == 0) {int cntt = 0; while (n % i == 0) {cntt++;n /= i;}a.push_back(fac(i, cntt));} }if (n > 1) {a.push_back(fac(n, 1));}return a;
}int main(){int x;cin >> x;vector<fac> a = divide(x);for (int i = 0; i < a.size(); i++) {cout << "p: " << a[i].p << " cnt: " << a[i].cnt << endl;}return 0;
}
素数筛选
Eratosthenes筛
bool notprime[N];
int prime[N];
void Eratos(int n) {notprime[1] = 1;prime[0] = 0;for(int i = 2; i <= n; i++) {if (!notprime[i]) {prime[++prime[0]] = i;}for (ll j = (ll)i * i; j <= n; j += i) {notprime[j] = 1;}}
}
欧拉筛(线性筛)
#include <cstdio>
#include <iostream>using namespace std;
const int maxn = 1e8 + 5;
int prime[maxn];
bool notprime[maxn];int n, q, k;
void sieve() {notprime[1] = 1;prime[0] = 0;for(int i = 2; i <= maxn; i++) {if (!notprime[i]) {prime[++prime[0]] = i;}for (int j = 1; j <= prime[0] && i * prime[j] <= maxn; j++) {notprime[i * prime[j]] = 1;if(i % prime[j] == 0) break;}}
}int main(){sieve();scanf("%d%d", &n, &q);while (q--) {scanf("%d", &k);printf("%d\n", prime[k]);}return 0;
}