组合基础与数论基础

注: logx=lnx

组合基础

  • 加法原理、乘法原理
  • 排列数 Anm=n!(nm)! : 从 1nm 个数排成一列的方案数
  • 组合数 Cnm=(nm)=n!(nm)!m! : 从1nm 个数的方案数。(相对于排列数不考虑顺序)
    • Cnm=Cnnm
    • Cnm=nm×Cn1m1
    • Cnm=Cn1m1+Cn1m (选第 n 个 + 不选第 n 个) (杨辉三角)
    • Cn0=1
    • Cn1=n
    • Cn2=(n1)n2
  • 二项式定理: (x+y)n=k=0nCnnkxnkyk

数论基础

  • 1n 大约有 nlnn 个质数,平均每 lnn 个数就有 1 个质数。
  • 找第一个大于或小于 n 的质数,直接从 n 开始枚举,然后用试除法判断,时间复杂度 O(nlogn)
  • 试除法、埃氏筛、线性筛。
  • 算数基本定理
  • n 是大于 1 的整数
    • 它的正约数集合是 {i=1mpibi},bi[0,ci]Z
    • 它的正约数个数为 i=1n(ci+1)
    • 它的正约数之和为 i=1m(j=0cipij)
  • 一个数 n 至多只有一个质因数大于 n
  • 一个数的因子总是成对出现,除完全平方数外。
  • 一个数 n 的因数个数小于 2n
  • 1n 每个数的约数个数总和大约有 nlogn 个。
  • gcd(na,nb)=ngcd(a,b),lcm(na,nb)=nlcm(a,b)
  • ab=gcd(a,b)lcm(a,b)
  • gcd(agcd(a,b),bgcd(a,b))=1,gcd(lcm(a,b)a,lcm(a,b)b)=1
  • a>b>0,gcd(a,b)=gcd(a,ab)=gcd(b,ab)
  • gcd(a,b)=gcd(b,amodb)

质数

质数又称素数。一个大于1的自然数,除了1和它自身外,不能被其他自然数整除的数叫做质数。

1n 大约有 nlnn 个质数,平均每 lnn 个数就有 1 个质数。

判定


根据素数的定义,可以写出一下代码,时间复杂度 O(n)

算法一,试除法:

bool is_prime(int x) {
    if(x < 2)
        return false;
    for(int i = 2; i * i <= x; i++)
        if(x % i == 0)
            return false;
    return true;
}

找第一个大于或小于 n 的质数,直接从 n 开始枚举,然后用试除法判断,时间复杂度 O(nlogn)

判断 1n 之间是否是质数,时间复杂度 O(nn) ,效率太低。


算法二:

bool v[N];
void solve_primes(int n) {
    memset(v, 0x00, siaeof(v));
    v[0] = v[1] = 1;
    for(int i = 2; i <= n; i++)
        for(int j = 2; i * j <= n; j++)
            v[i * j] = 1;
}

标记每个数的倍数,最后 vx=0x 是质数。但是和数会标记多次。

时间复杂度 O(i=1nni)=O(ni=1n1i)=O(nlogn) (调和级数)


算法三, Eratosthenes 筛:

bool v[N];
void solve_primes(int n) {
    memset(v, 0x00, siaeof(v));
    for(int i = 2; i <= n; i++)
        if(!v[i])
            for(int j = i; i * j <= n; j++)
                v[i * j] = 1;
}

标记每个质数的倍数。ji 开始是原来小于 i 的质数会标记 x * i , 其中 x < i
但是像 24 这样的数会被 2,3 多次标记。

时间复杂度 O(nloglogn) ,证明 alfayoung - 通俗易懂的埃氏筛时间复杂度分析


算法四, Euler 筛、线性筛:

int v[N];
::std::vector<int> ps;
void solve_primes(int n) {
    memset(v, 0x00, sizeof(v));
    for(int i = 2; i <= n; i++>)
    {
        if(!v[i])
            ps.push_back(v[i] = i);
        for(int j : ps)
            if(j > v[i] || i * j > n)
                break;
            else
                v[i * j] = j;
    }
}

用一个数的最小质因子来标记它,vx 表示 x 的最小质因子,ps1n 的质数。

每个合数 i×p 只会被它的最小质因子 p 筛一次,时间复杂度 O(n)

算数基本定理、唯一分解定理

n[2,+]Z,p1,p2,p3,...,pmP,c1,c2,c3,...,cmN+,i=1mpici=n.

任何一个大于 1 的正整数都能唯一分解为有限个质数的乘积。

n 是大于 1 的整数,它的正约数集合是 {i=1mpibi},bi[0,ci]Z

它的正约数个数为 i=1n(ci+1) 。每个质数选多少个,根据乘法原理乘起来。

它的正约数之和为 (p10+p12+p13++p1c1)×(pm0+pm2+pm3++pmcm)=i=1m(j=0cipij) 。每个质数选择若干次和其它的乘起来,变成一个因子,最后若干个因子加起来。

质因数分解

一个数 n 至多只有一个质因数大于 n 。反证法,对于正整数 n ,假设有 n 的两个因子 a,b>naba×b>n ,故假设不成立,则命题成立。

int ps[N], c[N], p;
void dec(int x) {
    p = 0;
    for(int i = 2; i * i <= x; i++)
        if(x % i == 0) {
            ps[++p] = i, c[p] = 0;
            while(x % i == 0)
                c[p]++, x /= i;
        }
    if(x > 1) // x 是质数,或者存在一个质因数大于 sqrt(x)
        ps[++p] = x, c[p] = 1;
}

时间复杂度 O(n)

n 的因子集合

一个数的因子总是成对出现,除完全平方数外。

::std::vector<int> div;
void sol(int x) {
    for(int i = 1; i * i <= x; i++)
        if(x % i == 0) {
            v.push_back(i);
            if(i * i != x)
                v.push_back(x / i);
        }
}

时间复杂度 O(n) ,根据时间复杂度可知,一个数 n 的因数个数小于 2n

1n 的因子集合

倍数法、刷表法 : 枚举一个数,看它是那个数的因数。

::std::vector<int> div[N];
void sol(int n) {
    for(int i = 1; i <= n; i++)
        for(int j = 1; i * j <= n; j++)
            div[i * j].push_back(i);
}

时间复杂度 O(n1+n2+n3++nn)=O(nlogn) ,根据时间复杂度可知,1n 每个数的约数个数总和大约有 nlogn 个。

约数与倍数

对于 a,bN,若存在 dN,使得 d|a,d|b,则称 da,b 的公因数、公因子、公约数。记 gcd(a,b) 为最大公因数。

对于 a,bN,若存在 dN,使得 a|d,b|d,则称 da,b 的公倍数。记 lcm(a,b) 为最小公倍数。

定理

根据定义,显然有 gcd(na,nb)=ngcd(a,b)lcm(na,nb)=nlcm(a,b)


定理 1

gcd(agcd(a,b),bgcd(a,b))=1

证明:

g=gcd(a,b) ,则有 k1,k2 满足
{gk1=agk2=b ,则原命题为 gcd(k1,k2)=1

反证法。假设 gcd(k1,k2)=c>1,则有 m1,m2 满足
{m1c=k1m2c=k2,则
{gm1c=agm2c=b,则 gcd(a,b)=gcgcd(m1,m2),与 gcd(a,b)=g 矛盾,故原命题成立。


定理 2

ab=gcd(a,b)lcm(a,b)

证明:
gcd(a,b)=g,lcm(a,b)=l

k1,k2 满足
{k1g=ak2g=b

gcd(k1,k2)=1l=k1k2glg=k1k2gglg=ab

则原命题得证。


定理 3

gcd(lcm(a,b)a,lcm(a,b)b)=1

证明:

lcm(a,b)gcd(a,b)=ablcm(a,b)a=bgcd(a,b),lcm(a,b)b=agcd(a,b)gcd(lcm(a,b)a,lcm(a,b)b)=gcd(agcd(a,b),bgcd(a,b))=1

则原命题得证。


定理 4 更相减损术

a>b>0,gcd(a,b)=gcd(a,ab)=gcd(b,ab)

证明:

设,集合 A,B,C 分别是 a,ba,abb,ab 的公因子集合。

对于 dA,有 k1,k2 满足
{k1d=ak2d=b,则 ab=(k1k2)d。所以 AB,AC

对于 dB,有 k1,k2 满足
{k1d=ak2d=ab,则 a+(a+b)=b=(k1k2)d。所以 BA,BC,又 AB,AC,所以 A=B=C,则原命题得证。


定理 5 辗转相除法、欧几里得算法

gcd(a,b)=gcd(b,amodb)

证明:

ab 时,命题显然成立。

a>b 时,有 a=kb+z,z=amodb。设,集合 A,B 分别是 a,bb,z 的公因子集合。

对于 dA,则 d|a,d|b,有 d|kb,则 d|(akb),即 d|z ,所以 AB
对于 dB,则 d|b,d|z,有 d|(akb),则 d|a,所以 BA,综上 A=B,则原命题得证。

本文作者:kuailedetongnian

本文链接:https://www.cnblogs.com/kuailedetongnian/p/18250728

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   kuailedetongnian  阅读(58)  评论(2编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起