数论(loading)
数论
数论
欧拉定理、费马小定理
欧拉函数(小于或等于n的正整数中与n互质的数的数目):
φ
(
x
)
=
x
∏
i
=
1
n
1
−
1
p
i
(
其
中
p
1
,
p
2
.
.
.
p
n
为
x
的
所
有
质
因
数
,
x
为
不
为
0
的
整
数
)
定
义
φ
(
1
)
=
1
\varphi(x)=x \prod_{i=1}^n{1- {1\over {p_i}}}(其中p_1,p_2...p_n为x的所有质因数,x为不为0的整数)\\定义\varphi(1)=1
φ(x)=x∏i=1n1−pi1(其中p1,p2...pn为x的所有质因数,x为不为0的整数)定义φ(1)=1
a φ ( m ) ≡ 1 ( m o d m ) ( g c d ( a . m ) = 1 ) a^{\varphi(m)}\equiv 1(mod\ m)(gcd(a.m)=1) aφ(m)≡1(mod m)(gcd(a.m)=1)当m为质数p且x不是p的倍数时即为费马小定理 x p − 1 ≡ 1 ( m o d p ) x^{p-1} \equiv1(mod\ p) xp−1≡1(mod p)
欧拉函数得出
/*
特性 :
1.若a为质数,phi[a]=a-1;
2.若a为质数,b mod a=0,phi[a*b]=phi[b]*a
3.若a,b互质,phi[a*b]=phi[a]*phi[b](当a为质数时,if b mod a!=0 ,phi[a*b]=phi[a]*phi[b])
*/
int m[n],phi[n],p[n],nump;
//m[i]标记i是否为素数,0为素数,1不为素数;p是存放素数的数组;nump是当前素数个数;phi[i]为欧拉函数
int main()
{
phi[1]=1;
for (int i=2;i<=n;i++)
{
if (!m[i])//i为素数
{
p[++nump]=i;//将i加入素数数组p中
phi[i]=i-1;//因为i是素数,由特性得知
}
for (int j=1;j<=nump&&p[j]*i<=n;j++) //用当前已得到的素数数组p筛,筛去p[j]*i
{
m[p[j]*i]=1;//可以确定i*p[j]不是素数
if (i%p[j]==0) //看p[j]是否是i的约数,因为素数p[j],等于判断i和p[j]是否互质
{
phi[p[j]*i]=phi[i]*p[j]; //特性2
break;
}
else phi[p[j]*i]=phi[i]*(p[j]-1); //互质,特性3其,p[j]-1就是phi[p[j]]
}
}
}
威尔逊定理
当 且 仅 当 p 为 素 数 时 : ( p − 1 ) ! ≡ − 1 ( m o d p ) 当且仅当p为素数时:(p -1)! ≡ -1 ( mod p ) 当且仅当p为素数时:(p−1)!≡−1(modp)
卢卡斯定理及其扩展
C m n m o d p = C m p n p C ( m m o d p ) ( n m o d p ) m o d p ( p 为 素 数 ) C_m^n \ mod \ p = C_{\frac{m}{p}}^{\frac{n}{p}}C_{(m \ mod \ p)}^{(n \ mod \ p)} \ mod \ p(p为素数) Cmn mod p=CpmpnC(m mod p)(n mod p) mod p(p为素数)
欧几里得定理及其扩展
欧几里得定理
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)
欧几里得扩展
a x + b y = g c d ( a , b ) = d ax+by=gcd(a,b)=d ax+by=gcd(a,b)=d在已知 a , b a,b a,b的情况下,求出一组解 x , y x,y x,y
a % b = a − a / b ∗ b a\%b=a-a/b*b a%b=a−a/b∗b
解法:
d
=
g
c
d
(
a
,
b
)
=
g
c
d
(
b
,
a
%
b
)
=
a
x
+
b
y
=
b
x
1
+
(
a
−
a
/
b
∗
b
)
y
1
\begin{aligned} d&=gcd(a,b)=gcd(b,a\%b)\\ &=ax+by=bx_1+(a-a/b*b)y_1\\ \end{aligned}
d=gcd(a,b)=gcd(b,a%b)=ax+by=bx1+(a−a/b∗b)y1
b x 1 + ( a − a / b ∗ b ) y 1 = b x 1 + a y 1 − ( a / b ) b y 1 = a y 1 + b ( x 1 − a / b y 1 ) \begin{aligned} bx_1+(a-a/b*b)y_1&=bx_1+ay_1-(a/b)by_1\\ &=ay_1+b(x_1-a/by_1)\\ \end{aligned} bx1+(a−a/b∗b)y1=bx1+ay1−(a/b)by1=ay1+b(x1−a/by1)
可 得 x = y 1 , y = ( x 1 − a / b y 1 ) 可得 x=y_1,y=(x_1-a/by_1) 可得x=y1,y=(x1−a/by1)
结论:
由欧几里得扩展得到一组特解 ( x 0 , y 0 ) (x_0,y_0) (x0,y0),那么有 a x 0 + b y 0 = d ax_0+by_0=d ax0+by0=d
方程通解为 x = x 0 + k ( b / d ) , y = y 0 − k ( a / d ) ( k 为 任 意 整 数 ) x=x_0+k(b/d),y=y_0-k(a/d)(k为任意整数) x=x0+k(b/d),y=y0−k(a/d)(k为任意整数)
那么 a x + b y = c ax+by=c ax+by=c仅当 d ∣ c d|c d∣c时有解,且解为 x = ( c / d ) x 0 + k ( b / d ) , y = ( c / d ) y 0 − k ( a / d ) x=(c/d)x_0+k(b/d),y=(c/d)y_0-k(a/d) x=(c/d)x0+k(b/d),y=(c/d)y0−k(a/d)
int exgcd(int a, int b, int &x, int &y) { //x,y初始为任意值,最后变为一组特解
if(b == 0) { //对应最终情况,a=gcd(a,b),b=0,此时x=1,y为任意数
x = 1;
y = 0;
return a;
}
int r = exgcd(b, a % b, x, y); //先递归到最终情况,再反推出初始情况
int t = x; x = y; y = t - a / b * y;
return r; //gcd(a,b)
}
线性同余方程
a x ≡ b ( m o d n ) ax≡b (mod \ n) ax≡b(mod n)
性 质 : d = g c d ( a , n ) , 若 d ∣ b , 则 方 程 恰 好 有 d 个 模 n 不 同 余 的 解 , 否 则 方 程 无 解 若 x 0 是 方 程 的 任 一 解 , 则 该 方 程 对 模 n 有 d 个 不 同 的 解 , 分 别 为 x i = x 0 + k ( b / d ) , ( k = 0 , 1 , 2 , … , d − 1 ) 性质:d=gcd(a,n),若d|b,则方程恰好有d个模n不同余的解,否则方程无解\\ 若x_0是方程的任一解,则该方程对模n有d个不同的解,分别为x_i=x_0+k(b/d),(k=0,1,2,…,d-1) 性质:d=gcd(a,n),若d∣b,则方程恰好有d个模n不同余的解,否则方程无解若x0是方程的任一解,则该方程对模n有d个不同的解,分别为xi=x0+k(b/d),(k=0,1,2,…,d−1)
解 法 : a x 0 + n y 0 = d , 利 用 扩 展 欧 几 里 得 求 出 一 组 特 解 ( x 0 , y 0 ) 然 后 , x = x 0 ( b / d ) % n 就 是 原 方 程 的 一 个 解 , 且 其 有 d 个 不 同 的 解 , 为 x i = ( x + k ( b / d ) ) % n , 0 < = k < d 解法:ax_0+ny_0=d,利用扩展欧几里得求出一组特解(x_0,y_0) 然后,x=x_0(b/d)\%n就是原方程的一个解,\\且其有d个不同的解,为x_i=(x+k(b/d))\%n,0<=k< d 解法:ax0+ny0=d,利用扩展欧几里得求出一组特解(x0,y0)然后,x=x0(b/d)%n就是原方程的一个解,且其有d个不同的解,为xi=(x+k(b/d))%n,0<=k<d
中国剩余定理
x ≡ a 1 ( m o d m 1 ) x ≡ a 2 ( m o d m 2 ) . . . x ≡ a n ( m o d m n ) x\equiv a_1(mod\ m_1)\\ x\equiv a_2(mod\ m_2)\\ ...\\ x\equiv a_n(mod\ m_n)\\ x≡a1(mod m1)x≡a2(mod m2)...x≡an(mod mn)
mi互质时
M = ∏ i = 1 n , M i = M m i , t i M i ≡ 1 ( m o d m i ) M=\prod_{i=1}^n,M_i=\frac{M}{m_i},t_iM_i\equiv1(mod\ m_i) M=∏i=1n,Mi=miM,tiMi≡1(mod mi)
x = k M + ∑ i = 1 n a i t i M i x=kM+\sum_{i=1}^na_it_iM_i x=kM+∑i=1naitiMi
int CRT(int a[], int m[], int n) {
int M = 1;
int ans = 0;
for(int i = 1; i <= n; i++) {
M *= m[i];
}
for(int i = 1; i <= n; i++) {
int x, y;
int Mi = M / m[i];
exgcd(Mi, m[i], x, y);
ans = (ans + Mi * x * a[i]) % M;
}
if(ans < 0) ans += M;
return ans;
}
mi不互质时
假设已求出前 k − 1 k-1 k−1个方程的解 x k − 1 x_{k-1} xk−1,设 M = L C M ( m i ) M=LCM(m_i) M=LCM(mi)
前 k − 1 k-1 k−1个方程满足 x k − 1 + t M ≡ a i ( m o d m i ) x_{k-1}+tM \equiv a_i(mod \ m_i) xk−1+tM≡ai(mod mi),即通解为 x = x k − 1 + t M x=x_{k-1}+tM x=xk−1+tM
求解第 k k k个方程则令 x k = x k − 1 + t M x_k=x_{k-1}+tM xk=xk−1+tM,代入可得 x k − 1 + t M ≡ a k ( m o d m k ) x_{k-1}+tM \equiv a_k(mod \ m_k) xk−1+tM≡ak(mod mk)
即 t M ≡ a k − x k − 1 ( m o d m k ) tM \equiv a_k -x_{k-1}(mod \ m_k) tM≡ak−xk−1(mod mk)
所以可以通过 e x g c d exgcd exgcd得到 t t t的值,然后得出 x k x_k xk的值
#define ll long long
ll Exgcd(ll a,ll b,ll &x,ll &y)
{
if(!b) {x=1,y=0;return a;}
ll gcd=Exgcd(b,a%b,x,y),tmp=x;
x=y,y=tmp-a/b*y;
return gcd;
}
ll Ex_crt()
{
ll lcm=mod[1],last_x=a[1],t;
for(int i=2;i<=k;i++)
{
ll lcm_a=((a[i]-last_x)%mod[i]+mod[i])%mod[i],x,y,k=lcm;
ll gcd=Exgcd(lcm,mod[i],x,y);
t=(x*lcm_a/gcd%(mod[i]/gcd)+(mod[i]/gcd))%(mod[i]/gcd);
lcm=lcm*mod[i]/gcd,last_x=(last_x+k*t)%lcm;
}
return (last_x%lcm+lcm)%lcm;
}
乘法逆元
若 a x ≡ 1 ( m o d n ) ax \equiv 1(mod \ n) ax≡1(mod n)则称 x x x是 m o d n mod \ n mod n意义下 a a a的乘法逆元,记 x = i n v ( a ) x=inv(a) x=inv(a)或 x = a − 1 x=a^{-1} x=a−1
可由欧拉定理,费马小定理,欧几里得扩展得逆元。
二次同余方程
x 2 ≡ n ( m o d p ) x^2 \equiv n(mod \ p) x2≡n(mod p),即 x 2 = n + k p x^2=n+kp x2=n+kp( p p p是奇质数)
用法: x 2 ≡ n ( m o d p ) → x ≡ n ( m o d p ) x^2 \equiv n(mod \ p)\rightarrow x \equiv \sqrt n (mod \ p) x2≡n(mod p)→x≡n(mod p),即若二次同余方程有解,n可以在 m o d p mod \ p mod p的意义下开根号。
引理: n p − 1 2 ≡ ± 1 ( m o d p ) n^{\frac{p-1}{2}}\equiv \pm 1(mod \ p) n2p−1≡±1(mod p)可由费马小定理经由平方差公式得到
勒让德符号: n p − 1 2 m o d p n^{\frac{p-1}{2} }mod \ p n2p−1mod p
若 n p − 1 2 ≡ 1 ( m o d p ) n^{\frac{p-1}{2}}\equiv 1(mod \ p) n2p−1≡1(mod p),则二次同余方程有解
找到一个 a a a满足 w = a 2 − n w=a^2-n w=a2−n为一个模 p p p的非二次剩余
得到 ( a + w ) p ≡ a p + w p − 1 2 w ≡ a − w ( m o d p ) (a+\sqrt w)^p \equiv a^p+w^{\frac{p-1}{2}}\sqrt {w} \equiv a-\sqrt w(mod \ p) (a+w)p≡ap+w2p−1w≡a−w(mod p)
所以
(
a
+
w
)
p
+
1
≡
(
a
+
w
)
p
(
a
+
w
)
≡
(
a
−
w
)
(
a
+
w
)
≡
a
2
−
w
≡
n
(
m
o
d
p
)
\begin{aligned} (a+\sqrt w)^{p+1}&\equiv (a+\sqrt w)^p(a+\sqrt w)\\ &\equiv(a-\sqrt w)(a+ \sqrt w)\\ &\equiv a^2 -w\\ &\equiv n(mod \ p) \end{aligned}
(a+w)p+1≡(a+w)p(a+w)≡(a−w)(a+w)≡a2−w≡n(mod p)
这里定义一个类似复数域的二次域,其中
i
2
=
a
2
−
n
=
w
i^2=a^2-n=w
i2=a2−n=w
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int t;
ll n, p;
ll w;
struct num { //建立一个复数域
ll x, y;
};
num mul(num a, num b, ll p) { //复数乘法
num ans = {0, 0};
ans.x = ((a.x * b.x % p + a.y * b.y % p * w % p) % p + p) % p;
ans.y = ((a.x * b.y % p + a.y * b.x % p) % p + p) % p;
return ans;
}
ll binpow_real(ll a, ll b, ll p) { //实部快速幂
ll ans = 1;
while (b) {
if (b & 1) ans = ans * a % p;
a = a * a % p;
b >>= 1;
}
return ans % p;
}
ll binpow_imag(num a, ll b, ll p) { //虚部快速幂
num ans = {1, 0};
while (b) {
if (b & 1) ans = mul(ans, a, p);
a = mul(a, a, p);
b >>= 1;
}
return ans.x % p;
}
ll cipolla(ll n, ll p) {
n %= p;
if (p == 2) return n;
if (binpow_real(n, (p - 1) / 2, p) == p - 1) return -1;//如果勒让德符号为-1,无解
ll a;
while (1) { //生成随机数再检验找到满足非二次剩余的a(勒让德符号为-1)
a = rand() % p;
w = ((a * a % p - n) % p + p) % p;
if (binpow_real(w, (p - 1) / 2, p) == p - 1) break;
}
num x = {a, 1};
return binpow_imag(x, (p + 1) / 2, p);
}
素数
反素数
任何小于 n n n的正数的约数个数都小于 n n n的约数个数,称 n n n为反素数。
由其特性可知, n = p 1 k 1 p 2 k 2 . . . p n k n n=p_1^{k_1}p_2^{k_2}...p_n^{k_n} n=p1k1p2k2...pnkn, p 1 = 2 , 且 k 1 ≥ k 2 ≥ k 3 ≥ . . . ≥ k n p_1=2,且k_1 \geq k_2 \geq k3 \geq ... \geq k_n p1=2,且k1≥k2≥k3≥...≥kn
极端情况为 n = p 1 p 2 . . . p n n=p_1p_2...p_n n=p1p2...pn,枚举到最大 n n n的 p n p_n pn即可,最多枚举到 n = 2 k n=2^k n=2k,k次即可。
具体实现:
- 当前走到的数字已经大于我们想要的数字了
- 当前因子大于我们想要的因子了
- 当前因子正好是我们想要的因子(此时判断是否需要更新最小 )
然后 dfs 里面不断一层一层枚举次数继续往下迭代
欧拉筛
void euler_sieve_with_phi(int n)
{
totPrimes = 0;
phi[1] = 1;
memset(flag, 0, sizeof(flag));
for (int i = 2; i <= n; i++)
{
if (!flag[i])
{
primes[totPrimes++] = i;
phi[i] = i - 1;
}
for (int j = 0; i * primes[j] <= n; j++)
{
flag[i*primes[j]] = true;
if (i % primes[j])
phi[i*primes[j]] = phi[i] * (primes[j] - 1);
else
{
phi[i*primes[j]] = phi[i] * primes[j];
break;
}
}
}
}
素性测试
Miller Rabin:
bool millerRabbin(int n) {
if (n < 3) return n == 2;
int a = n - 1, b = 0;
while (a % 2 == 0) a /= 2, ++b;
// test_time 为测试次数,建议设为不小于 8
// 的整数以保证正确率,但也不宜过大,否则会影响效率
for (int i = 1, j; i <= test_time; ++i) {
int x = rand() % (n - 2) + 2, v = quickPow(x, a, n);
if (v == 1 || v == n - 1) continue;
for (j = 0; j < b; ++j) {
v = (long long)v * v % n;
if (v == n - 1) break;
}
if (j >= b) return 0;
}
return 1;
}