数论(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 \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+(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 ) \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+(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 ) \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 )(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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值