数论(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)=xi=1n1pi1(p1,p2...pnxx0)φ(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) xp11(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(p1)!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=aa/bb

解法:
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 d=gcd(a,b)=gcd(b,a%b)=ax+by=bx1+(aa/bb)y1 d=gcd(a,b)=gcd(b,a%b)=ax+by=bx1+(aa/bb)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 ) bx1+(aa/bb)y1=bx1+ay1(a/b)by1=ay1+b(x1a/by1) bx1+(aa/bb)y1=bx1+ay1(a/b)by1=ay1+b(x1a/by1)

可 得 x = y 1 , y = ( x 1 − a / b y 1 ) 可得 x=y_1,y=(x_1-a/by_1) x=y1,y=(x1a/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=y0k(a/d)(k)

那么 a x + b y = c ax+by=c ax+by=c仅当 d ∣ c d|c dc时有解,且解为 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)y0k(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) axb(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)dbdnx0ndxi=x0+k(b/d),(k=0,1,2,,d1)

解 法 : 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,dxi=(x+k(b/d))%n0<=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)\ xa1(mod m1)xa2(mod m2)...xan(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,tiMi1(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 k1个方程的解 x k − 1 x_{k-1} xk1,设 M = L C M ( m i ) M=LCM(m_i) M=LCM(mi)

k − 1 k-1 k1个方程满足 x k − 1 + t M ≡ a i ( m o d   m i ) x_{k-1}+tM \equiv a_i(mod \ m_i) xk1+tMai(mod mi),即通解为 x = x k − 1 + t M x=x_{k-1}+tM x=xk1+tM

求解第 k k k个方程则令 x k = x k − 1 + t M x_k=x_{k-1}+tM xk=xk1+tM,代入可得 x k − 1 + t M ≡ a k ( m o d   m k ) x_{k-1}+tM \equiv a_k(mod \ m_k) xk1+tMak(mod mk)

t M ≡ a k − x k − 1 ( m o d   m k ) tM \equiv a_k -x_{k-1}(mod \ m_k) tMakxk1(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) ax1(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=a1

可由欧拉定理,费马小定理,欧几里得扩展得逆元。

二次同余方程

x 2 ≡ n ( m o d   p ) x^2 \equiv n(mod \ p) x2n(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) x2n(mod p)xn (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) n2p1±1(mod p)可由费马小定理经由平方差公式得到

勒让德符号: n p − 1 2 m o d   p n^{\frac{p-1}{2} }mod \ p n2p1mod p

n p − 1 2 ≡ 1 ( m o d   p ) n^{\frac{p-1}{2}}\equiv 1(mod \ p) n2p11(mod p),则二次同余方程有解

找到一个 a a a满足 w = a 2 − n w=a^2-n w=a2n为一个模 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 )pap+w2p1w aw (mod p)

所以
( a + w ) p + 1 ≡ ( a + w ) p ( a + w ) ≡ ( a − w ) ( a + w ) ≡ a 2 − w ≡ n ( m o d   p ) (a+w)p+1(a+w)p(a+w)(aw)(a+w)a2wn(mod p) (a+w )p+1(a+w )p(a+w )(aw )(a+w )a2wn(mod p)
这里定义一个类似复数域的二次域,其中 i 2 = a 2 − n = w i^2=a^2-n=w i2=a2n=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,k1k2k3...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次即可。

具体实现:

  1. 当前走到的数字已经大于我们想要的数字了
  2. 当前因子大于我们想要的因子了
  3. 当前因子正好是我们想要的因子(此时判断是否需要更新最小 )

然后 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; }

__EOF__

本文作者waby
本文链接https://www.cnblogs.com/waby/p/15857128.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   waby  阅读(38)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示