|算法讨论|数论数学 学习笔记

模板及讲解

欧几里得算法

求gcd(a, b),即a和b的最大公倍数
欧几里得算法:

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

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

ax+by=gcd(a,b) 的解 x,y
扩展欧几里得算法:
已求出下一个状态一组解 x1,y1 使得 bx1+(a%b)y1=gcd(a,b)
a%b=aabb ,得
bx1+(aabb)y1=gcd(a,b)
bx1+ay1by1ab=gcd(a,b)
ay1+b(x1y1ab)=gcd(a,b)
对照 ax+by=gcd(a,b) ,可得
x=y1,y=x1y1ab
由欧几里得算法终止条件 a=gcd(a,b),b=0 得, a1+b0=gcd(a,b)
所以x,y的边界值是 10
通解:

x=x0+bgcd(a,b)ty=y0agcd(a,b)t

int egcd(int a, int b, int &x, int &y)
{
    if (b==0)
    {
        x = 1;
        y = 0;//边界值
        return a;//求最大公倍数
    }
    int temp = x;
    int ans = egcd(b,a%b,x,y);
    x = y;
    y = temp-y*a/b;//公式计算
    return ans;
}

求不定方程 ax+by=c 的最小一组解 x,y
先求出 g=gcd(a,b)
如果 c%g0 ,无解
否则,将不定方程两边同时除以 g ,得 a1x+b1y=c1
此时 gcd(a1,b1)=1 ,可用扩展欧几里得算法求出 a1x1+b1y1=1 的解 x1,y1
a1x+b1y=c1 的一组解为 x1c1,y1c1
求最小解可用一组特解模 b 即可得到

求a 关于 m 的乘法逆元
ax1(modn)
由同余性质得, ax1=ny
变形,得 axny=1 ,此时 gcd(a,n) 必须为 1 且只有唯一解, 否则无解
即可使用扩展欧几里得算法求解

中国剩余定理

设正整数 m1,m2,...,mk 两两互素,则同余方程组

xxxa1a2ak(modm1)(modm2)(modmk)

有整数解。并且在模 M=m1m2...mk 下有唯一解,
解为
x(a1M1M11+a2M2M12+...+akMkM1k)(modM)

其中 Mi=MmiM1i Mi mi 下的逆元

解法:先 O(n) 的时间求出 M ,然后求出 Mi , 用扩展欧几里得算法求出 M1i ,根据公式进行计算

int crt(int n, int *a, int *m)
{
    int ans = 0;
    int M = 1;
    for (int i=1;i<=n;i++) M *= m[i];
    for (int i=1;i<=n;i++)
    {
        int Mi = M/m[i];
        int x,y;
        e_gcd(Mi, m[i], x, y);//求Mi的逆元x
        ans = (ans + a[i]*Mi*x)%M;
    }
    return (ans+M)%M;
}

筛选法求质数

int vis[n];
int sx()
{
    int m = sqrt(n+0.5);
    ms(vis,0);
    for (int i=2;i<=n;i++)
    if (!vis[i]) for (int j=i*i;j<=n;j+=i) vis[j] = 1;
}

欧拉函数

给出n的唯一分解式 n=pa11pa22pa33...pakk , 求出 123...n 中与n互素的数的个数

公式(容斥原理):

φ(n)=S(p1,p2,...pk)(1)|s|npiSpi

可变形为:
φ(n)=n(11p1)(11p2)...(11pk)

即可在 O(k) 的时间复杂度算出 φ(n)


不给出唯一分解式求 φ(n)
根据变形的公式,可以枚举所有小于 n 的因子,然后之后把他”除干净”即可

int phi(int n)
{  
    int ans = n;//ans为最后的答案
    int m = (int)sqrt(n+0.5);
    for (int i=2;i<=m;i++) if (n%i==0)
    {
        ans = ans/i*(i-1);//ans初值为n,因为1-(1/p) = (p-1)/p,由变形后公式可得
        while (n%i==0) n/=i;//除干净
    }
    if (n>1) ans = ans/n*(n-1);
    return ans;
}  

用筛选法在 O(nloglogn) 时间复杂度求1~n中所有数的欧拉phi函数值:

int phitable(int n, int* phi)
{
    for (int i=2;i<=n;i++) phi[i] = 0;
    phi[1] = 1;
    for (int i=2;i<=n;i++) if (!phi[i])
    for (int j=i;j<=n;j+=i)
    {
        if (!phi[j]) phi[j] = j;
        phi[j] = phi[j]/i*(i-1);
    }   
}

求正约数的个数

给出n的唯一分解式 n=pa11pa22pa33...pakk , 求出 n 的正约数的个数
根据乘法原理, n 的正约数的个数为

i=1k(ai+1)

快速幂

int fastpow(int a,int b)
{  
    int ans=1,base=a;  
    while(b!=0){  
        if(b&1!=0)  
        ans*=base;  
        base*=base;  
        b>>=1;  
    }  
    return ans;  
}  

排列

一般地,从 n 个不同元素中取出 m(1mn) 个元素,按照一定的顺序排成一列,叫做从 n 个元素中取出 m 个元素的一个排列(顺序不同是不同的两种方案)
(约定 0!=1 )

1 无重排列
n 个不同元素中有序且不重复取出 k(1kn) 个元素,称为 n 个不同元素中取出 k 个元素的一个无重排序,简称k-排列,所有这样的排列个数记为 Akn

Akn=n!(nk)!

2 全排列
(1) 无重
当k-排列中的 k=n
Ann=n!

3 重复排列
n 个不同元素中有序且可重复取出 k(1kn) 个元素,称为 n 个不同元素中取出 m 个元素的一个无重排序,简称k-可重排列
重复排列个数为

nk

4 圆周排列
n 个不同元素中无重复地取出 k(1kn) 个元素排在一个圆周上,称为 n 个不同元素的一个圆周排列,简称k-圆排列
圆周排列个数为

Pknk=n!k(nk)!

组合

一般地,从 n 个不同元素中取出 m(1mn) 个元素组成一组,叫做从 n 个元素中取出 m 个元素的一个组合(顺序不同是相同的两种方案)
(约定 0!=1 )

1 无重组合
n 个不同元素中无序且不重复取出 k(1kn) 个元素,称为 n 个不同元素中取出 k 个元素的一个无重组合,简称k-组合,所有这样的排列个数记为 Ckn

Ckn=Aknk!=n!k!(nk)!

2 重复组合
n 个不同元素中无序但可重复取出 k(1kn) 个元素,称为 n 个不同元素中取出 k 个元素的一个重复组合,简称k-可重组合
重复组合个数为

Ckn+k1=(n+k1)!k!(n1)!

概率

1 数学期望

随机变量 X 的数学期望 E(X) 就是所有可能值按照概率加权的和。

E(X)=i=1nxipi

你可能感兴趣的:(数学/数论,算法讨论)