数论总结

定理/性质

1 ~ n:nln(n) (实际偏小,越趋近于+ 越准确,估计复杂度是够的)

约数个数定理

定义g(x),为x的约数个数
对于一个数i,可分解成若干质数幂次的乘积,即
i=prime[1]aprime[2]b.....
g(i)=(a+1)(b+1)......

整除的基本性质

a|b b|c   =>   a|c
a|b a|c   =>   a|bc
a|b a|c   =>   a|ib±jc   (a|b,c的线性组合)
a|b b|a   =>   a=±b

a=ib±c => 公因子(a,b)=公因子(b,c)

  • 证明
    • 假设d为b,c的公因子,即d|b,d|c
    • 则 d|ib±c=a,即d|a
    • 由d|b得 d=公因子(a,b)=公因子(b,c)
    • 反之,如果d是a,b的公因数,也能证出d是b,c的公因数

互素性质

  • ab,c=>abc
  • pp|ab=>p|a  or  p|b
  • ab|c  and  gcd(a,c)=1=>b|c
  • gcd(ak,b)=1  {k>=1}=>gcd(a,b)=1
  • a1(modb)=>gcd(a,b)=1

算术基本定理

  • 任何一个大于1的自然数n,都可以唯一分解成有限个质数的乘积
  • n=pr11pr22...prkk
  • p1<p2<...<pk,r1,r2,...rk

模运算

  • (a+b)  mod  n=(a  mod  n+b  mod  n)  mod  n
  • (ab)  mod  n=(a  mod  nb  mod  n)  mod  n
  • ab  mod  n=(a  mod  n)b  mod  n
  • 切记 除法运算 不能模运算!!!

算法

欧几里得算法(gcd)

辗转相除

function gcd(a,b:longint):longint;
begin
 if b=0
 then gcd:=a
 else gcd:=gcd(b,a mod b);
end;

辗转相减(更相减损术/Stein算法)

  • a为偶数,b为奇数 gcd(a,b)=gcd(a/2,b)
    a为奇数,b为偶数 gcd(a,b)=gcd(a,b/2)
    a为偶数,b为偶数 gcd(a,b)=2*gcd(a/2,b/2)
    a为奇数,b为奇数 gcd(a,b)=gcd(b,a-b) {a>b}
    (a或b=0 返回另一个值)或(a=b返回a或b)
  • 证明gcd(a,b)=gcd(b,a-b)
    • a=b+(a-b)=>(a,b)=(b,a-b) {整除性质}
function gcd(a,b:longint):longint;
begin
 if a=0 then exit(b)
 else
  if b=0 then exit(a)
  else
   if a=b then exit(a);
 if a mod 2=0
 then
  if b mod 2=0
  then gcd:=2*gcd(a div 2,b div 2)
  else gcd:=gcd(a div 2,b)
 else
  if b mod 2=0
  then gcd:=gcd(a,b div 2)
  else
   if a>b
   then gcd:=gcd(b,a-b)
   else gcd:=gcd(b,b-a);
end;
  • 优点:
    • 加法,减法和移位运算,是最基本的运算,时间消耗最小
    • 乘法,除法,取余运算较慢

扩展欧几里得算法(exgcd)

  • 求不定方程 ax+by=1 的一组解的方法

  • ax1+by1=gcd(a,b)=gcd(b,amod b)=bx2+[aa/bb]y2=ay2+b(x2y2a/b)

  • =>x1=y2

  • =>y1=x2y2(a / b)
procedure exgcd(a,b:int64;var d,x,y:int64);
var t:int64;
begin
  if b=0
  then
   begin d:=a; x:=1; y:=0; end
  else
   begin exgcd(b,a mod b,d,x,y); t:=x; x:=y; y:=t-y*(a div b); end;
end;
  • 用途:
    • 1)求解不定方程;
    • 2)求解模线性方程(线性同余方程);
    • 3)求解模的逆元;

1)求解不定方程

利用扩展欧几里得算法求解不定方程 ax+by=n 的整数解的求解全过程,步骤如下:

  • (1)先计算 Gcd(a,b) ,若n不能被 Gcd(a,b) 整除,则方程无整数解;否则,在方程两边同时除以 Gcd(a,b) ,得到新的不定方程 a2x+b2y=n2 此时 Gcd(a2,b2)=1;

  • (2)利用扩展欧几里德算法求出方程 a2x+b2y=1 的一组整数解 x0,y0 ,则 n2x0,n2y0a2x+b2y=n2

  • (3)根据数论中的相关定理,可得方程 a2x+b2y=n2 的所有整数解为:
    x=n2x0+b2t
    y=n2y0a2t (t=0,1,2)
    调整得到正整数解

最小公倍数(lcm)

  • lcma,b=ab/gcd(a,b)

快速幂

  • 其实就是倍增的思想
  • a1,a2,a4...a2n
  • 所以快速+幂/乘/加 都可以

ab mod n

  • b and 1 取出二进制下最后一位
  • b shr   1 去掉二进制下最后一位
  • ab=a2n......a16a8a4a2
  • 每次求出 a2i,1a2i
function f(a,b,n:int64):int64;  //(a^b) mod n
var t,y:int64;
begin
 t:=1;
 y:=a;
 while b<>0do
  begin
  if(b and 1)=1
  then t:=t*y mod n;
   y:=y*y mod n;
   b:=b shr 1;
  end;
 exit(t);
end;

[acbd]n

矩阵乘法求斐波那契数列
[F[N1]F[N]]=[acbd][F[N2]F[N1]]

{F[N1]=aF[N2]+bF[N1] F[N]=cF[N2]+dF[N1]
a=0b=1c=1d=1
[F[N1]F[N]]=[0111][F[N2]F[N1]]
[F[N1]F[N]]=[0111]N1[F[0]F[1]]

var
 x:array[0..100000000]of longint;
 i,j,k,n:longint;
 t,y:array[1..2,1..2]of int64;
function g(f:longint):longint;
var a,b,c,d:longint;
begin
 t[1,1]:=1; t[1,2]:=0; t[2,1]:=0; t[2,2]:=1;
 y[1,1]:=0; y[1,2]:=1; y[2,1]:=1; y[2,2]:=1;
 k:=1000000007;
 while f<>0 do
  begin
   if (f and 1)=1
   then begin
    a:=(t[1,1]*y[1,1]+t[1,2]*y[2,1])mod k;
    b:=(t[1,1]*y[1,2]+t[1,2]*y[2,2])mod k;
    c:=(t[2,1]*y[1,1]+t[2,2]*y[2,1])mod k;
    d:=(t[2,1]*y[1,2]+t[2,2]*y[2,2])mod k;
    t[1,1]:=a mod k; t[1,2]:=b mod k; t[2,1]:=c mod k; t[2,2]:=d mod k;
   end;
   a:=(y[1,1]*y[1,1]+y[1,2]*y[2,1])mod k;
   b:=(y[1,1]*y[1,2]+y[1,2]*y[2,2])mod k;
   c:=(y[2,1]*y[1,1]+y[2,2]*y[2,1])mod k;
   d:=(y[2,1]*y[1,2]+y[2,2]*y[2,2])mod k;
   y[1,1]:=a mod k; y[1,2]:=b mod k; y[2,1]:=c mod k; y[2,2]:=d mod k;
   f:=f shr 1;
  end;
 exit((x[1]*t[2,1]+x[0]*t[2,2])mod k);
end;

begin
 readln(n);
 k:=1000000007;
 x[0]:=1; x[1]:=1;
 writeln(g(n-1));
 for i:=2 to n do
  x[i]:=(x[i-1]+x[i-2])mod k;
 writeln(x[n]);
end.

矩阵乘法优化递推式

例如 a[n]=a[n1]+a[n2]+5
a[N1]a[N]1=110100501a[N2]a[N1]1

线性筛

var
 prime:array[0..3562115]of longint;
 check:array[0..60000000]of boolean;
 i,j:longint;
 n,len:longint;
begin
 readln(n);
 for i:=2 to n do
  begin
   if check[i]=false
   then begin inc(len); prime[len]:=i; end;
   for j:=1 to len do
    begin
     if i*prime[j]>n then break;
     check[i*prime[j]]:=true;
     if i mod prime[j]=0 then break;
    end;
  end;
 writeln(len);
 for i:=1 to len do
  write(prime[i]);
end.

判断素数

O(N)

我们知道对于一个的他的因子的大小不超过 N ,所以线性筛预处理,再取模判断即可

O(log2n)

  • :p  apa(modp)ap11(modp)
  • a,2<a<p,ap(modp)

欧拉函数

性质

  • φ(n)nn(1)
  • anaφ(n)1(mod  n)
  • pφ(p)=p1φ(1)=1
  • 积性函数
    • mnφ(nm)=φ(n)φ(m)
    • n=pkpφ(n)=pkp(k1)=p(k1)(p1)
  • nφ(2n)=φ(n)
  • d|n φ(d)=n
  • φ(n)=npp|np1p

O(N)1nφ(i)

const
 maxn=1000000;
var
 check:array[0..maxn]of boolean;
 phi,prime:array[0..maxn]of longint;
 n,i,j,ans,len:longint;
begin
 readln(n);
 len:=0;
 for i:=2 to n do
  begin
   if check[i]=false
   then begin inc(len); phi[i]:=i-1; prime[len]:=i; end;
   for j:=1 to len do
    begin
     if prime[j]*i>n
     then break;
     check[i*prime[j]]:=true;
     if i mod prime[j]=0
     then begin phi[i*prime[j]]:=phi[i]*prime[j]; break; end
     else phi[i*prime[j]]:=phi[i]*(prime[j]-1);
    end;
  end;
 for i:=1 to n do
  writeln(phi[i]);
end.

O(n)φ(n)

const
 maxn=1006350;
var
 check:array[0..maxn]of boolean;
 prime:array[0..maxn]of longint;
 i,j:longint;
 n,s,ans,len,t:longint;
begin
 readln(n);
 s:=n; ans:=n; n:=trunc(sqrt(n)); len:=0;
 for i:=2 to n do
  begin
   if check[i]=false
   then begin inc(len); prime[len]:=i; end;
   for j:=1 to len do
    begin
     if prime[j]*i>n
     then break;
     check[prime[j]*i]:=true;
     if i mod prime[j]=0
     then break;
    end;
  end;
 for i:=1 to len do
  begin
   if s mod prime[i]=0
   then
    begin
     ans:=(ans div prime[i])*(prime[i]-1);
     while s mod prime[i]=0 do
      s:=s div prime[i];
    end;
  end;
 if s<>1
 then ans:=(ans div s)*(s-1); //1700016764
 writeln(ans);
end.

莫比乌斯函数

性质

  • n
    d|nμ(d)={10d=1d>1
  • n:
    d|nμ(d)d=φ(n)n

O(N)1nμ(i)

const
 maxn=100000;
var
 check:array[0..maxn]of boolean;
 mu,prime:array[0..maxn]of longint;
 i,j,len,n:longint;
begin
 readln(n); mu[1]:=1; len:=0;
 for i:=2 to n do
  begin
   if check[i]=false
   then begin mu[i]:=-1; inc(len); prime[len]:=i; end;
   for j:=1 to len do
    begin
     if i*prime[j]>n
     then break;
     check[i*prime[j]]:=true;
     if i mod prime[j]=0
     then begin mu[i*prime[j]]:=0; break; end
     else mu[i*prime[j]]:=-mu[i];
    end;
  end;
 for i:=1 to n do
  writeln(i,' ',mu[i]);
end.

求解模方程组

中国剩余定理可以求解模数互质的情况,但根据ydc的课件,我们用其他方式合并

{x  mod  a1=b1x  mod  a2=b2

{x=a1x1+b1x=a2y1+b2

a1x1+b1=a2y1+b2

扩展欧几里得求出 x1
b=a1x1+b1  a=lcm(a1,a2)
然后我们合并为 x  mod  a=b

求逆元

求逆元的方法汇总

你可能感兴趣的:(数论—快速幂,数论—矩阵乘法,数论—裴蜀定理,模板/总结,数论—筛法,数论—中国剩余定理,数论—(扩展)欧几里得算法,数论—更相减损术,数论—最大公约数/最小公倍数,数学—欧拉函数,数论—莫比乌斯相关,数论—莫比乌斯反演)