算法——数论(自然数、整除、公约数、同余、素数)

时间:2020-12-30 00:34:33

自然数和整数

  自然数从0开始,每个自然数都有一个后继。如果一组关于自然数的命题对0成立,且对任意自然数都可以推导出对其后继成立,则该命题对全部自然数成立。(数学归纳法)

  负整数∪自然数=整数

整除

如果一个整数a能被另一个整数d整除,记作d|a,这意味着存在某个整数k,使得a=kd。

  • 如果d|a,则对于任意自然数k都有d|ka;
  • 如果d|a且d|b,则d|(a±b)
  • 如果a|b且b|a,则a=b

特殊的整除:

  • 如果2能整除a的最末尾,则2|a;如果4能整除a的最后两位,则4|a,因为4|100;如果8能整除a的最后三位,则8|a,因为8|1000;……
  • 如果5能整除a的最末尾,则5|a;如果25能整除a的最后两位,则25|a;如果125能整除a的最后3位,则125|a;……
  • 如果3能整除a的个位数字之和,则3|a;如果9能整除a的各位数字之和,则9|a;
  • 如果11能整除a的偶位数字之和与奇位数字之和的差,则11|a。

公约数和公倍数

  • 如果d是a的约数且是b的约数,则d是a与b的最大公约数。
  • 如果m是a的倍数并且也是b的倍数,则m是a与b的公倍数。

最大公约数

  所有公约数中最大的一个,记作gcd(a,b)。

    • gcd(a, ka) = |a|;
    • 对任意整数a与b,如果d|a并且d|b,则d|gcd(a,b)
    • 对所有整数a和b以及任意非负整数n,gcd(an,bn)=n*gcd(a,b)
    • 对所有正整数d,a和b,如果d|ab并且gcd(a,d)=1,则d|b
    • 如果a=bq+r,则gcd(a,b)=gcd(b,r)

最小公倍数

  所有公倍数中最小的那个,记作lcm(a,b)

    • lcm(a,b)=a*b/gcd(a,b)

辗转相除法求最大公约数和最小公倍数

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

int lcm(int a, int b)
{
    if (a * b == 0)
    {
        return 0;
    }
    return a * b / gcd(a, b);
}

同余

  设m是正整数,a,b是整数,如果m|(a-b),则称a和b关于模m同余,记作a≡b(mod m)

同余的性质

  • a≡a(mod m)【自反性】
  • 如果a≡b(mod m),则b≡a(mod m)【交换性】
  • 如果a≡b(mod m)且b≡c(mod m),则a≡c(mod m),因为m|(a-b+b-c)【传递性】
  • 如果a≡b(mod m)且c≡d(mod m),则a±c≡b±d(mod m),ac≡bd(mod m)【结合性】
  • 如果a≡b(mod m),则an≡bn(mod m),n∈N

  • 如果ac≡bc(mod m),则a≡b(mod (m/gcd(c,m))
  • 如果a≡b(mod m)且d|m,则a≡b(mod d)【更小的约数】

  • 如果a≡b(mod m),则ad≡bd(mod m)【数乘】

  • 如果a≡b(mod mi),i=1,2,…,n,l=lcm(m1,m2,…,mn),则a≡b(mod l)

  • 如果p为素数,则ap ≡ a(mod p);如果gcd(a,p)=1,则ap-1 ≡ 1(mod p)

素数

  自然数中,除了1之外,只能被1和该数自身整除的数

    • 其他
    • 2是最小的素数
    • 2是唯一一个偶素数

  筛法求素数

const int MAX = 10000;
bool prime[MAX + 1];

void searchprime()
{
    memset(prime, true, sizeof(prime));
    prime[1] = false;

    for (int i = 2; i <= (int)floor(sqrt(MAX)); ++i)
    {
        if (prime[i])
        {
            int j = i * 2;
       // 标记所有的i的倍数为非素数
while (j <= MAX) { prime[j] = false; j += i; } } } }

  素数的判定

    • 原始的判定方法,根据素数的定义
    • 改进的判定方法1,x可以分解为两个整数a,b的积,即 x=a*b,a≤b,那么a ≤sqrt(x)
    • 改进的判定方法2,其实2到x的平方根中那些合数也是没有必要用来判断的。如果事先生成一个素数表,循环的次数还可以降低。利用素数表来求解。
bool method_1(int num)
{
    for (int i = 2; i < num; i++)
    {
        if (num % i == 0)
        {
            return false;
        }
    }
    return true;
}

bool method_2(int num)
{
    int max = (int)floor(sqrt(num));
    for (int i = 2; i <= max; i++)
    {
        if (num % i == 0)
        {
            return false;
        }
    }
    return true;
}

bool method_3(int num)
{
    int max = (int)floor(sqrt(num));
    int i = 0;
    while (list[i] <= num)
    {
        if (num % i == 0)
        {
            return false;
        }
        i++;
    }
    return true;
}