ARZhu的数论初步

数论

2017年3月4日02:11:35

gcd

1. 原理:

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

2. 代码

int gcd( int a, int b ) {
    if( b == 0 ) return a; return gcd( b, a % b );
}

3. 时间复杂度:

O(log n)

4. 预处理

d[3000][3000] 中所有两个数的gcd

d[i][j] = d[i][j-i];

预处理时间复杂度O(n^2)

5. 应用

1.

给一个数a,找一个(0,a)范围内的数b,gcd(a,b)=1,用a和b做辗转相减次数不超过60
(i) 构造: 直接找质数b;
(ii)gcd( b, a % b ) => O( log n )
使gcd( b, a - b ) 与gcd( b, a % b )时间复杂度一样,则自然想到斐波那契数列
例如
一组斐波那契数:
1, 1, 2, 3, 5, 8, 13, 21;
辗转相处过程:
21, 13 => 13, 8 => 8, 5 => 5, 3 => 3, 2
fib[i] / fib[ i - 1 ] -> 黄金分割,所以构造a * 0.618 附近的数

2. 斐波那契数列性质
gcd( fib[i], fib[j] ) = fib[ gcd( i, j )];
3.区间gcd
(一)

给出数组A,询问区间gcd
n < 1e5, A[i] < 1e9

线段树:

dL, dR;//左右两个子树的gcd
d = gcd( dL, dR );

时间复杂度:O(nlog^2n)

ST表:
维护区间[l, l + 2^i )
询问[ l, r ]的gcd,找最大的i满足2^i <= r - l + 1

gcd( [ l, l + 2^i ), [ r - l ) )
(二)

区间加,询问区间最大公约数
n, m <= 10 ^ 5

思想:差分;

gcd( a, b, c ) => gcd( a, b - a, c - b)
A:[ l , r ] gcd( A[l], B: [ l + 1, r])

对于数组A, 区间加 询问单点的值
对于数组B, 单点修改 询问区间gcd => 线段树

(三)

给出数组A,询问其区间gcd有多少种取值
n<=1e5,A[i]<=1e9

exgcd和中国剩余定理

exgcd

1.描述:

给出a 和b,解方程

ax + by = ( a,b )

2.求解过程

  1. 求解出一组x0, y0;
  2. 得出所有解
x = x0 + t * b / ( a, b )
y = y0 - t * a / ( a,b )

事实上

  1. b = 0 ( a, b ) = a => x = 1, y = 0
原方程等价于 b * x0 + ( a % b ) * y0 = ( a, b ) 
化简成 a * x + b * y = b * x0 + ( a % b ) * y0
而又有 a % b = a - [ a / b ] * b
得 a * x + b * y = b * x0 + a * y0 - [ a / b ] * b * y0
移项得 a * ( x - y0 ) = b * ( x0 - [ a / b ] * y0 - y ) 
令 x = y0
   y = x0 - [ a / b ] * y0
构造出一组解 

中国剩余定理

1. 描述

事实上,以上的过程都可以表示成

a * x = b ( mod m )

2. 求解一个过程

  1. 而当gcd( a, m ) 不是 b 的约数时显然无解
  2. 当( a, m ) | b
解出 a * X + m * Y = ( a, m )
然后解出
x = X * b / ( a, m )
y = Y * b / ( a, m )

3. 真正的中国剩余定理

x = a[i] ( mod b[i] )//有一堆
求解

例如

x = a1 ( mod b1 )
x = a2 ( mod b2 )
 
使两个常数 c1, c2
有 x = a1 * b2 * c1 + a2 * b1 * c2
b2 * c1 = 1 mod b1
b1 * c2 = 1 mod b2

同样的,三组时候
有 x = a1 * b2 * b3 * c1 + a2 * b1 * b3 * c2 + a3 * b1 * b2 * c3

费马小定理

1. 描述

对于质数p,任意a∈[1, p - 1],a ^ ( p - 1 ) = 1 ( mod p )

2. 逆元(应用)

逆元定义

对于数a, b,如果存在最小整数x,使a * x = 1 ( mod b ),那么称x是a模的逆元

应用

所以直接用 a ^ ( p - 2 ) mod p 快速幂即可(可以避免exgcd)

欧拉定理

1. 描述

欧拉定理是费马小定理的拓展
欧拉函数 φ ( n ) 表示[1, n]范围内与 n 互质的数。对于任意质数 p, φ ( p ) = p - 1
欧拉定理 对于任意正整数 m, a∈[1, m - 1], gcd(a, m) = 1,都有a^φ ( m ) = 1 ( mod m )
当m为质数是,就是费马小定理的情况。所以欧拉定理是费马小定理的拓展。

2. 求φ( m )(应用)

  1. 当( a, b ) = 1 φ( a * b ) = φ( a ) * φ( b )
  2. φ( p ^ t ) = ( p - 1 ) * p ^ ( t - 1 )
    与10互质 => 与2互质
    所以将m分解质因数,结合 φ( p ) = p - 1,运用上述公式,可以求得。复杂度O( m ^ 0.5 )

3. 逆元(应用)

a的逆元就是 a^( φ ( m ) - 1) mod m

二项式系数和简单排列组合

1. 描述

C( n, m ) 从 n 个不同的球中选 m 个出来的方案数
递推式
C( n , m ) = C( n - 1, m - 1 ) + C( n - 1, m )
代码实现:

for( int i = 0 ; i <= n ; ++ i ) {
    C[i][0] = 1;
    for( int j = 1 ; j <= i ; ++ j ) {
        C[i][j] = C[i - 1][j] + C[i - 1][j - 1];
    }
}

2. 二项式定理

对于展开 ( x + y ) ^ n, x ^ i * y ^ ( n - i ) 的系数是 C( n, i )
[杨辉三角]

**ex **对于展开 ( x + y + z ) ^ n, x ^ a * y ^ b * z ^( n - a - b ) 的系数是C( n ,a ) * C( n - a, b)

高斯消元

描述

一个方程组,如
3x + 4y = 10 ①
x + y = 3 ②
手算 消元求方程

过程:
x[i, j] 第 i 个方程第 j 个未知数的系数

  1. 先找一个方程k,满足 x[k, 1] != 0
  2. 用这个方程把僧下的方程的第一个未知数消掉
  3. 再看其他系数
    代码实现:
for( int i = 1 ; i <= N ; ++ i ) {
    int where = 0;
    for( int j = i ; j <= N ; ++ j )
        if ( x[j][i] != 0 ) {
            where = j;
            break;
        }
    for( int j = 0 ; j <= N ; ++ j ) swap( x[where][j], x[i][j] );
    for( int j = i + 1 ; j <= N ; ++ j ) {
        double k1 = x[j][i] / x[i][i];
        for( int k = 0 ; k <= N ; ++ k ) x[j][k] -= k1 * x[i][k];
    }
}
//此时第 i 个方程只和i ~ n 个变量有关
for( int i = N ; i ; -- i ) {
    ans[i] = x[i][0];
    for( int j = i + 1 ; j <= N ; ++ j )
        ans[i] -= x[i][j] * ans[j];
    ans[i] /= x[i][i];
}
//当找不到系数不为零的时候,那么就是无解或者无限解
posted @ 2017-03-06 20:13  ARZhu  阅读(307)  评论(1)    收藏  举报