码迷,mamicode.com
首页 > 其他好文 > 详细

常用数论知识整理

时间:2015-10-08 14:34:04      阅读:166      评论:0      收藏:0      [点我收藏+]

标签:

 

1) 素数

 

基础理论

Theorem 素数有无限多个

Proof. 若存在最大素数P_max , 设 X = (P_1 * P_2 …… * P_max) + 1,此时如果X为素数, 则X > P_max, 矛盾, 如果X为合数, 则必存在它的一个素因子 P_X 且 P_X > P_max, 矛盾。

 

Theorem

 技术分享

显然是在越大的范围内分布得越稀疏的。

 

 

素数的判定

暴力的方法即枚举每个小于n的数位约数, 简单的优化即 枚举 2~sqrt(n) 的所有质数。

由于一些伪素数令费马小定理的逆定理不成立, 而去背一张伪素数表又不是很优美, miller-rabin 算法随之产生。

///////////////////////////////////////////////////////////////////

强伪素数
设n是一个大于4的奇整数,s和t是使得(n-1)=2^s*t的正整数,其中t为奇数,设B(n)是如下定义的整数集合:
a属于集合B(n)当且仅当2≤a≤n-2且

1: a^tmodn=1
2: 存在整数i,0<=i<s满足a^((2^i)*t) mod n=n-1
当n为素数时, 任意a在2和n-1中,均有a属于集合B(n)
当n为合数时,若a属于集合B(n),则称n为一个以a为底(基)的强伪素数,称a为n素性的强伪证据。
n为素数,说明它对所有底均为强伪素数

 

Btest(a,n){
//n为奇数,返回true。即返回真说明n是强伪素数
   s←0; t ←n-1; //t开始为偶数
     repeat
         s++;t ← t÷2;
   until t mod 2 = 1; //n-1=2st     t为奇数
          x ←at mod n;
   if x=1 or x=n-1 then return true;    //满足①or②。
   for i ←1 to s-1 do{
         x ←x2 mod n;
         if x=n-1 then return true; //满足②,
   }
   return false;}

 


 

通过这一定义则发现,小于1000的奇合数中,随机选到一个强伪证据的概率小于1%
更重要的是,对任一奇合数,强伪证据比例都很小
所以,我们可以多次运行下面的算法,就可把错误概率降低我们可控制的范围


MillRab(n) { //奇n>4,返回真时表示素数,假表示合数
a←uniform(2..n-2);
return Btest(a,n);   //测试n是否为强伪素数
}//该算法是3/4-正确,偏假的。


 


RepeatMillRob(n,k){
      for i ←1 to k do
    if MillRob(n) =false then
     return false; //一定是合数
    return true;
}

 

虽然miller-rabin 是一个随机性算法, 但是取前9个素数就可以保证在 10^18范围内的正确性了。

代码很简单

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#define ll long long
using namespace std;
int t, prim[15] = {0, 2, 3, 5, 7, 11, 13, 17, 19, 23};
ll u;
ll mypow(ll x, ll k, ll mod){
ll ret = 1;
while(k){
if(k & 1) (ret *= x) %= mod;
(x *= x) %= mod;
k >>= 1;
}return ret;
}
bool MR(ll a, ll n){
if(a >= n) return 1;
ll w = mypow(a, u, n);
if(w == 1) return 1;
for(int i = 0; i < t; i ++){
if(w == n - 1) return 1;
(w *= w) %= n;
} return 0;
}
bool pd(ll n){
if(n == 2) return 1;
if(n < 2 || (!(n & 1))) return 0;
t = 0; u = n - 1;
while((u & 1) == 0) u >>= 1, t ++;
for(int i = 1; i <= 9; i ++) if(!MR(prim[i], n)) return 0;
return 1;
}
int main(){
int N;
while(scanf("%d", &N) != EOF){
int cnt = 0;
for(int i = 1; i <= N; i ++){
ll x; scanf("%I64d", &x);
if(pd(x)) cnt ++;
}
printf("%d\n", cnt);
}
return 0;
}

  

 

 筛法

求 不超过 n 的所有质数。

首先可以把每个数miller-rabin 判一下, 时间复杂度 O(nlogn)

考虑筛法。 直接的想法是每筛出一个质数, 就把它的倍数中小于n 的数标记为合数, 时间复杂度 O(nln(n))

在上面的筛法中, 一些还有多个质因子的素数会多次被筛掉,  产生了很多无用的花费。 如何减少冗余? 直接的想法就是把每个合数标记且仅标记一次, 不妨用它最小的那个质因子去筛掉它。

于是有了一种优化的筛法: 枚举每一个数, 枚举之前筛出来过的质数, 把它们的乘积标记为合数, 如果当前数是当前质数的倍数, 则break掉。

这样做每个合数只会被自己最小的质因子筛掉。因为两者乘积的最小质因子要么是枚举的那个质数, 要么是枚举的整数的最小质因子,故在break之前筛掉的那些合数的最小质因子都是枚举的那个质数, 但是如果不break的话,之后筛掉的那些合数的最小质因子就是整数的最小质因子而不是那个枚举的质数了。

 

	for(int i = 2; i <= n; i ++){
if(!isprim[i]) prim[++ pp] = i;
for(int j = 1; j <= pp && i * prim[j] <= n; j ++){
isprim[i * prim[j]] = 1;
if(i % prim[j] == 0) break;
}
}

  

 

 

2) 最大公约数

 

 

欧几里得算法

 

gcd(a, b) = gcd(b, a % b)

若 m | a 且 m | b (a >= b),则 m | a - b, 则 m | a - k*b (k >= 0 且 k*b <= a)

 

求不定方程 ax + by = m 的解。

如果 m  不是 gcd(a, b) 的倍数, 那么原方程显然不存在整数解。

故问题转化为 ax + by = gcd(a, b)

设 ax1 + by1 = gcd(a, b); bx2 + (a % b)y2 = gcd(b, a % b)

-> ax1 + by1 = bx2 + (a%b)y2 (欧几里得原理) 

下面我们要把原式中的求模去掉以获得 x1, y1 的值。

-> ax1 + by1 = bx2 + (a - [a / b] * b) y2

       = ay2 + b(x2 - [a / b] y2)

所以我们可以通过递归得到 x1, y1 的一组解, 边界是 b = 0 时, 这时原式退化成了一个一元方程, 显然有 x = 1, y = 0

代码

int exgcd(int a, int b, int &x, int &y){
if(!b){x = 1, y = 0; return a;}
int r = exgcd(b, a % b, x, y), t = x;
x = y, y = t - (a / b) * y;
return r;
}

设x0, y0 是不定方程 ax + by = m 的一组解, (a, b) = g, 那么解集为

{(x0 + b * t / g, y0 + a * t / g) : t ∈ z}

这样就可以获得需要任意解了。

 

 

线性同余方程组

技术分享

 

如果m1, m2 …… mn 两两互质, 可以使用中国剩余定理。

中国剩余定理说明:假设整数m1< /sub>,m2, ... ,mn两两互质,则对任意的整 数:a1,a< /em>2, ... ,an,方程组技术分享有解,并且通解可以用如下方式构造得到:

技术分享
是 整数m1,m< /em>2, ... ,mn的乘积,并设
技术分享
是除了mi以外的n- 1个整数的乘积。
技术分享
技术分享
技术分享的数论倒数
技术分享
方程组
技术分享的通解形式为
技术分享
在模M的意义下, 方程组(S) 只有一个解:
技术分享

 

这个定理的正确性是很显然的。 对于原式中的每一项i, 在模 mi 的意义下都只有它自己这一项贡献了 ai * ti * mi , 即 ai * 1, 其它项都是 mi 的倍数。 所以每个式子模 mi 都会是 ai.

 

当然在 m1 …… mn 不满足两两互质是中国剩余定理是不能用的, 连逆元都求不出来。

还有一种更直接的方法, 不过复杂度是 O(logn) 的。

考虑前两个式子 x  a1 (mod m1) 和 x ≡ a2 (mod m2) 

可以写成 m1 * k1 + a1 = x ,  m2 * k2 + a2 = x

即 m1 * k1 + a1 = m2 * k2 + a2

即 m1 * k1 - m2 * k2 = a2 - a1

设 g = gcd(m1, m2),  l = lcm(m1, m2)

m1 * k1 / g - m2 * k2 / g = (a2 - a1) / g

这时候就可以用扩欧 求出 k1, k2 的一组解, 然后把k1带回到原式中, 这样这个同余方程组就合并成了这样一个同余方程:

 x  ≡ a1 + m1 * k1 (mod lcm(m1, m2))

 

 

逆元

设正整数 m,对于任意正整数 a 满足 (a , m ) = 1,总存在惟一的 b 满足a × b 1
(mod m ) 且 1 b < m,称 b 为m 意义下的逆元。

逆元应用在模意义下的整数除法中。

逆元的计算主要是两种方法

一种是直接根据定义 b : a * b ≡ 1 (mod m)用扩欧算出来。

或者是用费马小定理

a ^ (p - 1) ≡ 1 (mod p)

-> a ^ (p - 2) ≡ 1 / p (mod p)

当然用费马小定理求的时候必须保证 p 是一个质数, 扩欧求得时候保证 a 和 p 互质就可以了。

 

 

3) 数论函数

 

在数论上,算术函数(或称数论函数)指定义域为正整数、陪域为复数的函数,每个算术函数都可视为复数的序列。(嗯我并不知道这句话是什么意思,,)


技术分享

莫比乌斯函数

 μ 的积性是很显然的

有定理:

Σ(d|n) μ(d) = [n = 1]

不知道有什么用

这个定理可以推出这个式子 : μ * {1} = e

 

 莫比乌斯反演公式

技术分享

技术分享

以上分别是莫比乌斯反演的两种形态。

证明

数论函数 e(n) = [n = 1]

-> f * e = f , μ * {1} = e

->f(n) = Σ(d|n) g(d) 即 f = g * {1}

    g(n) = Σ(d|n) μ(d) * f(n / d) 即 g = f * μ

-> f * μ = g * {1} * μ = g * e = g

    g * {1} = f * μ * {1} = f * e = f

得证

 

 莫比乌斯函数与容斥原理

设 f(n) = ∑(d|n) φ(d), 由下面欧拉函数中的定理, f(n) = n

又 φ(n) = ∑(d|n) μ(d) * f(n / d), 即 φ(n) = ∑(d|n) μ(d) * n / d

通过例子感性地解释莫比乌斯反演:

考虑不超过n的正整数k,根据欧拉函数的定义,我
们要算出有多少k与n互质。
令gcd(n, k) =??,当??>1要被去除,考虑质数集合
??={2,3,5,7,11,13,…},??>1时显然会是??中某些
质数的倍数且 p 中不会含有平方因子。若??|??,可知满足这样条件的k有n/??个。
这些是需要去掉的,但很容易发现中间有重复。

对于有两个质因子的p, 要加上 n/ p, 有三个的要再减去 n / p …… 有 t 个的要加上 (-1) ^ t  * (n / p)

发现这其实就是莫比乌斯反演推出来的那个式子!

真是非常优美的。

 

欧拉函数

 

欧拉定理 

对于互质的正整数 a 和 n ,有 aφ(n)  ≡ 1 mod n  。

证明:

消去律:如果 gcd(c,p) = 1 ,则 ac ≡ bc mod p ⇒ a ≡ b mod p 。

( 1 ) 令 Zn = {x1, x2, ..., xφ(n)} , S = {a * x1 mod n, a * x2 mod n, ... , a * xφ(n) mod n} ,
        则 Zn = S 。
        ① 因为 a 与 n 互质, xi (1 ≤ i ≤ φ(n)) 与 n 互质, 所以 a * xi  与 n 互质,所以 a * xi  mod n ∈ Zn 。
        ② 若 i ≠ j , 那 么 xi ≠ xj< /sub>,且由 a, n互质可得 a * xi mod n ≠ a * xj mod n (消去律)。

( 2 )     aφ(n) * x* x2 *... * xφ(n) mod n 
      ≡ (a * x1) * (a * x2) * ... * (a * xφ(n)) mod n
      ≡ (a * x1 mod n) * (a * xmod n) * ... * (a * xφ(n) mod n) mod n
      ≡  x* x* ... * xφ(n) mod n
      对比等式的左右两端,因为 xi  (1 ≤ i ≤ φ(n)) 与 n 互质,所以 aφ (n)  ≡  1 mod n (消去律)。
o(≧v≦)o~~好棒

 

费马小定理即欧拉定理 n 为质数时的一个特殊情况。

 

两个定理

 ∑(d|n) φ(d) = n

当n>1时, 1…n中与n互质的整数和为 n * φ(n) / 2
 

欧拉函数的积性

n = a * b, gcd(a, b) = 1, 则:

φ(n) = φ(a) * φ(b)

证明:

对于≤n 的每一个正整数, 都可以表示成 u = a * q + r (0 <= q < b, 1 <= r <= a)

如果要证明 gcd(u , n) = 1, 等价于证明 gcd(u, a) = 1 且 gcd(u, b) = 1

考虑保证 gcd(u, a) = 1, 即对于每一个确定可取的 q, 这里的 r 都与a 不互质, 当且仅当u 与 a不互质

-> 对于每一个确定可取的 q, r都有 φ(a) 种取法。

下面考虑保证 gcd(u, b) = 1, 这是我们将 r 的取值确定, 对于 u1 = a * q1 + r, u2 = a * q2 + r, 如果 q1 != q2, 有u1 != u2 (mod n)。

反证  若 u1 = u2(mod n) ->  a * q1 = a * q2(mod n) -> q1 = q2 (mod n) (消去率), 矛盾。

所以Sn = {u1, u2 …… ub} = {1, 2, …… b}, 故ui 中与b 互质的数有 φ(b) 个。

-> 对于每一个确定可取的 r, q都有 φ(b) 中取法。

综上, φ(n) = φ(a) * φ(b)

 

欧拉函数通式

(1) p^k 的欧拉函数为  p^k - p^(k - 1)

这个很显然, 在 p^k 个数中 p 的倍数一共有 p^(k - 1) 个

(2) 若 gcd(p, q) = 1, 则 φ(p * q) =  φ(p) *  φ(q)

积性函数的性质, 刚才已经证过了。

(3)结合前两条, 显然可以得出任意整数的欧拉函数的公式:

若 n = pi^ki, 则φ(n) = (pi^ki - pi^(ki - 1)) = pi^ki * (1 - 1/pi) = n * (1 - 1/pi)

 

 

4)原根

 

设(a, m) = 1, 则满足 a^r = 1 (mod m) 的最小正整数 r 叫做 a 模 m 的阶。

有比较显然的定理 : 若 r 为 a 模 m 的阶, 且a^k = 1 (mod m), 当且仅当 r | k。

又有: r 为 a 模 m 的阶 当且仅当以下两条件成立:

1, a^r = 1(mod m)

2, 对于每个r 的质因子 p, 有 a^(r/p) != 1(mod m)

这个也是很显然的吧,,

 

原根

若整數a模m的階爲φ(m),則a叫做是模m的原根

 

定理:对于正整数m,模m具有原根当且仅当m= 2;4;pa;2pa

其中p是奇素数且a >= 1。

 

因为原根通常很小 , 一般用枚举来找原根。

 

奇质数的所有原根

定理:如果p为素数,那么素数p一定存在原根,并且p的原根的个数为phi(p-1).< /p>

 

设m是正整数,a是整数,若a模m的阶等于φ(m),则称a为模m的一个原 根.


假设一个数g对于P来说是原根,那么g^i mod P的结果两两不同,且 有 1<g<P, 0<i<P,那么g可以称为是P的一 个原根,归根到底就是g^(P-1) = 1 (mod P)当且< /span>

仅当指数为P-1的时候成立.(这里P是素数).

求原根目前的做法只能是从2开始枚举,然后暴力判断g^(P-1) = 1& nbsp;(mod P)是否当且当指数为P-1的时候成立。而由于原根一般都不大,所以可以暴力得 到.

 

求一个奇素数的所有原根方法。

设g是P的平方非剩余,技术分享是P-1的标准分解式,若恒有技术分享成立,

则g就是P的原根。

 

 

5) 组合数求模

n * m 可以接受的话就直接 nm DP。

如果 m 比较小(m * logP 可以接受的话)直接把分子和分母都列出来算就好了(分子分母的数量都是 O(m)级的)对于分子和分母上的每一个数把它是P的素因子的因子都单独提出来求, 其它的直接乘到一起分母再乘一个逆元就可以了。

n, m都非常大且P为质数的时候就可以用Lucas定理了

技术分享

就是把n, m都转化为 P 进制然后每一位单独算就好了, 很简单实用。

下面的问题是如果n, m都很大但P是合数怎么办T T。 显然如果这个合数的每个质因子的质数都<=1的话直接CRT合并一下就好了, 所以下面问题在于如何求 C(n, m) % (P ^ c)

技术分享

 

 

 

 

参考资料

数论pdf  by 王迪

贾志鹏线性筛

JZPKIL解题报告 by gyz

孙子定理 百度百科

数论的欧拉定理证明 csdn 蓬蒿人

常用数论知识整理

标签:

原文地址:http://www.cnblogs.com/lixintong911/p/4860756.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!