首页 > 技术文章 > 数学问题(一)

gtarcoder 2015-10-22 16:03 原文

1. 辗转相除法/欧几里得算法

    用辗转相除法求两个整数的最大公约数。记 gcd(a,b) 为两个数a和b的最大公约数。辗转相除法的理论依据为: gcd(a, b) = gcd(b, a % b). 
    因为设t为a和b的最大公约数,则 a = mt, b = nt, m和n互斥,a = k*b + a%b, k = a/b. 那么 mt = k*nt +a%b,于是a%b可以被t整除,则t为b和a%b的公约数,设 a%b = rt. 
    t = gcd(b, a%b) <==> n 和 r 互斥 
由mt = k*nt + rt, 若 n和r不互斥,则设 n = ps, r = qs, s != 1,于是得到 m 可以被s整除,即 m和n不互斥,与之前的结论矛盾! 
因此 gcd(a, b) = gcd(b, a%b)

算法实现

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

 

2. 扩展辗转相除法

    整数a和b,最大公约数为gcd(a,b),一定有 ax + by = gcd(a, b)。如何求出x和y呢? 
     设 bx' + a%b*y' = gcd(b, a%b),根据欧几里得定理有bx' + a%b*y' = gcd(b, a%b) = gcd(a, b) = ax + by,则有bx' + a%b*y' = ax + by。 
由于 a%b = a - a / b,因此 bx' + (a - a/b)y' = ax + by,即 ay' + b(x' - a/b*y') = ax + by,则有 
x = y' 
y = x' - a/b*y' 
于是,可以在求得满足bx' + a%b*y' = gcd(b, a%b)的x'和y'之后再继续求出x和y,当b = 0时, x = 1, y = 0即可返回。

算法实现

//返回a和b的最大公约数,同时返回时的x和y满足 ax + by = gcd(a, b)
int extgcd(int a, int b, int& x, int& y){
    if (b == 0){
        x = 1;
        y = 0;
        return a;
    }
    int d = extgcd(b, a % b, y, x);
    y -= (a/b)*x;
    return d;
}

 

3. 模运算

    注意在某些环境下,若a为负数,则 a%m的结果也是负数,因此若想要得到a%m在[0, m-1)范围内的值,可以使用 (m + a % m) %m。 
    a和b对m同余,可以表示为 a = b(mod m)。假设a=c(mod m), b = d(mod m),那么有以下基本规律: 
a + b = c + d(mod m) 
a - b = c - d(mod m) 
a x b = c x d(mod m)

4. 快速幂算法

    求一个整数x的n次方 xn,若n表示为2进制为n=ktkt1....k1k0(b)n=2kii1+2ki2+... 
xn=x(2ki1+2ki2+...) = x2ki1x2ki2x2ki3... 
于是,可以按照幂次从低到高依次计算出来x2ki,然后在n的二进制表示中若ki为1,则最后的结果需要乘以 x2ki

long long mod_pow(long long x, long long n, long long m){
    long long res = 1;
    while(n >  0){
        if (n & 1)
            res = res * x % m;
        x = x * x % m;
        n >= 1;
    }
    return res;
}

 

5. 矩阵的幂

typedef vector<int> vec;
typedef vector<vec> mat;
typedef long long int ll;
const int M = 10000;

//计算 A*B
mat mul(mat& A, mat& B){
    mat C(A.size(), vec(B[0].size()));
    for(int i = 0; i < A.size(); i ++){
        for(int k = 0; k < B.size(); k ++){
            for(int j = 0; j < B[0].size(); j ++){
                C[i][j] = (C[i][j] + A[i][k]*B[k][j]) % M;
            }
        }
    }
    return C:
}
//计算A^n
mat pow(mat A, ll n){
    mat B(A.size(), vec(A.size()));
    for(int i = 0; i < A.size(); i ++){
        B[i][i] = 1;
    }
    while(n > 0){
        if (n & 1)
            B = mul(B, A);
        A = mul(A, A)
        n >= 1;
    }
    return B;
}

 

 

推荐阅读