NOIP专题复习——专题八:数论基础

快速幂

把指数二进制分解,把乘法运算的次数减小到 logn 的级别。

int pow(int x, int y, int p){
    int res = 1;
    for( ; y; x = (x*x)%p, y >>= 1) if(y&1) res = (res * x) % p;
    return res;
}

欧几里得算法

最大公约数

定理:

两个整数的最大公约数等于其中较小的那个数和两数相除余数的最大公约数。
最大公约数( greatest common divisor )缩写为 gcd
gcd(a,b)=gcd(b,a%b)

证明:

不妨设 a>b r=a%b , r 不为0。

a=kb+r

r=akb

假设 d a,b的公约数,则:

rd=adkbd

显然等式右边为整数,所以 d|r ,因此 d 也是b,a%b的公约数
假设 d b,a%b的公约数,则:

d|b,d|(akb)

显然 d|a ,因此d也是a,b的公约数
gcd(a,b)=gcd(b,a%b) 得证。

代码:

int gcd(int a, int b){
    if(b == 0) return a;
    return gcd(b, a % b);
}
//时间复杂度:O(log n)

拓展欧几里得

定理:

对于不完全为 0 的非负整数 a,b gcd(a,b) 表示 a,b 的最大公约数,必然存在整数对 x,y ,使得 gcd(a,b)=ax+by

证明:

不妨设 a>b,A>B
因为 ax+by=gcd(a,b) gcd(a,b)=gcd(b,a%b)
考虑递归的过程,令 a=bb=a%b
所以

bx+(a%b)y=gcd(b,a%b)=gcd(a,b)=ax+by

即:

bx+(a%b)y=ax+by

bx+(aabb)y=ax+by

bx+ayabby=ax+by

ay+b(xaby)=ax+by

解得:

x=y   y=xaby

代码:

int exgcd(int a, int b, int &x, int &y){
    if(b == 0){
        x = 1, y = 0;
        return a;
    }
    int GCD = exgcd(b, a%b, x, y);
    int xx = x;
    x = y, y = xx - a/b * y;
    return GCD;
}
//时间复杂度:O(log n)

应用

求乘法逆元

ax+by=gcd(a,b)

gcd(a,b)=1 时,在 modb 的同余系下,有:

ax+by1modb

ax1modb

所以当 gcd(a,b)=1 时, a 存在modb意义下的乘法逆元, a1=x

求解线性同余方程

线性同余方程是最基本的同余方程,“线性”表示方程的未知数次数是一次,即形如:

axbmodp

此方程有解当且仅当 b 能够被 a p 的最大公约数整除。
这时,如果 x0 是方程的一个解,那么所有的解可以表示为:

x0+kn/d|(kz)

其中 d a p 的最大公约数。在模 n 的完全剩余系 0,1,,n1 中,恰有 d 个解。
假如gcd(a,p)=d,我们可以把 a,b,p 同除以 d ,使得gcd(a,p)=1

axbmodp

xba1modp

中国剩余定理

中国剩余定理可以求出以下的一元线性同余方程组中 x 的一个解:

(S):xxxa1modm1a2modm2a1modm1

假设整数 m1,m2,...,mn 两两互质,则对任意的整数: a1,a2,...,an ,方程组 (S) 有解,并且通解可以用如下方式构造得到:
M=ni=1mi ,并设 Mi=Mmi ti=M1imodmi
即:

xi=1naitiMimodM

欧拉函数

定义:

在数论,对正整数n,欧拉函数是小于等于n的数中与n互质的数的数目。

求解公式:

phi(n)=n×p11p1×p21p2×...×pn1pn
其中 pi 表示 x 的质因数。

性质:

  1. 不完全积性函数:ϕ(ab)=ϕ(a)ϕ(b),其中 gcd(a,b)=1

    • d|nϕ(d)=n
    • 欧拉定理: aϕ(p)1modp
    • ϕ(n)=i=1n[gcd(i,n)=1]=i=1nk|n,k|iμ(k)=k|nμ(k)nk
    • 代码:

      求解单个:

      typedef long long ll;
      bool is[100010];
      ll prime[100010], cnt;
      ll n;
      ll phi(ll x){
          ll ans = x, i;
          for(i = 1; prime[i] <= x && i <= cnt; i ++){
              if(x % prime[i] == 0) ans = ans/prime[i]*(prime[i]-1);
              while(x % prime[i] == 0) x /= prime[i];
          }
          if(x != 1) ans = ans/x*(x-1);
          return ans;
      }
      void init(){
          is[1] = is[0] = 1;
          for(int i = 2; i <= 100000; i ++){
              if(!is[i]) prime[++cnt] = i;
              for(int j = 1; j <= cnt; j ++){
                  if(i*prime[j] >= 100000) break;
                  is[i*prime[j]] = 1;
                  if(i % prime[j] == 0) break;
              }
          }
      }

      线性筛法:

      typedef long long ll;
      const ll N = 10000000;
      bool is[N+10];
      int prime[N+10], cnt;
      int phi[N+10];
      ll n, ans;
      void init(){
          phi[1] = 1;
          is[1] = is[0] = 1;
          for(int i = 2; i <= N; i ++){
              if(!is[i]) prime[++cnt] = i, phi[i] = prime[cnt]-1;
              for(int j = 1; j <= cnt; j ++){
                  if(i*prime[j] >= N) break;
                  is[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);
              }
          }
      }
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值